提交 5fc1ee2f 编写于 作者: A Anton Perkov

Merge branch 'master' into HEAD

......@@ -21,3 +21,6 @@
path = externals/binaryen
url = https://github.com/EOSIO/binaryen
[submodule "libraries/softfloat"]
path = libraries/softfloat
url = https://github.com/eosio/berkeley-softfloat-3
# Defines EOS library target.
project( EOS )
cmake_minimum_required( VERSION 2.8.12 )
enable_testing()
......@@ -7,8 +8,10 @@ enable_testing()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libraries/fc/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
INCLUDE( VersionMacros )
INCLUDE( SetupTargetMacros )
include( GNUInstallDirs )
include( VersionMacros )
include( SetupTargetMacros )
include( InstallDirectoryPermissions )
set( BLOCKCHAIN_NAME "Eos" )
set( CMAKE_CXX_STANDARD 14 )
......@@ -17,8 +20,8 @@ set(VERSION_MAJOR 3)
set(VERSION_MINOR 0)
set(VERSION_PATCH 1)
set( CLI_CLIENT_EXECUTABLE_NAME eos_client )
set( GUI_CLIENT_EXECUTABLE_NAME eos )
set( CLI_CLIENT_EXECUTABLE_NAME eosioc )
set( GUI_CLIENT_EXECUTABLE_NAME eosio )
set( CUSTOM_URL_SCHEME "gcs" )
set( INSTALLER_APP_ID "68ad7005-8eee-49c9-95ce-9eed97e5b347" )
......@@ -45,6 +48,33 @@ if (USE_PCH)
include (cotire)
endif(USE_PCH)
# add defaults for openssl
if ("${OPENSSL_ROOT_DIR}" STREQUAL "")
if (NOT "$ENV{OPENSSL_ROOT_DIR}" STREQUAL "")
set(OPENSSL_ROOT_DIR $ENV{OPENSSL_ROOT_DIR})
set(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/include)
elseif (APPLE)
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
set(OPENSSL_INCLUDE_DIR "/usr/local/opt/openssl/include")
elseif(UNIX AND NOT APPLE)
set(OPENSSL_ROOT_DIR "/usr/include/openssl")
set(OPENSSL_INCLUDE_DIR "/usr/include/openssl/include")
else()
message(FATAL_ERROR "openssl not found and don't know where to look, please specify OPENSSL_ROOT_DIR")
endif()
endif()
if ("${OPENSSL_LIBRARIES}" STREQUAL "")
if (NOT "$ENV{OPENSSL_LIBRARIES}" STREQUAL "")
set(OPENSSL_LIBRARIES $ENV{OPENSSL_LIBRARIES})
elseif (APPLE)
set(OPENSSL_LIBRARIES "/usr/local/opt/openssl/lib")
elseif(UNIX AND NOT APPLE)
set(OPENSSL_LIBRARIES "/usr/include/openssl")
else()
message(FATAL_ERROR "openssl libs not found and don't know where to look, please specify OPENSSL_LIBRARIES")
endif()
endif()
if(UNIX)
if(APPLE)
......@@ -114,12 +144,6 @@ if( WIN32 )
else( WIN32 ) # Apple AND Linux
find_library(READLINE_LIBRARIES NAMES readline)
find_path(READLINE_INCLUDE_DIR readline/readline.h)
#if(NOT READLINE_INCLUDE_DIR OR NOT READLINE_LIBRARIES)
# MESSAGE(FATAL_ERROR "Could not find lib readline.")
#endif()
if( APPLE )
# Apple Specific Options Here
message( STATUS "Configuring Eos on OS X" )
......@@ -164,19 +188,24 @@ if(ENABLE_COVERAGE_TESTING)
find_program( GENHTML_PATH NAMES genhtml)
endif()
add_subdirectory( externals )
include(wasm)
include(installer)
add_subdirectory( externals )
add_subdirectory( contracts )
add_subdirectory( libraries )
add_subdirectory( contracts )
add_subdirectory( plugins )
add_subdirectory( programs )
add_subdirectory( scripts )
add_subdirectory( tests )
add_subdirectory( tools )
add_subdirectory( debian )
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/genesis.json ${CMAKE_CURRENT_BINARY_DIR}/genesis.json COPYONLY)
install(FILES genesis.json DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/eosio/node_00)
install_directory_permissions(DIRECTORY ${CMAKE_INSTALL_FULL_SYSCONFDIR}/eosio)
install_directory_permissions(DIRECTORY ${CMAKE_INSTALL_FULL_SYSCONFDIR}/eosio/node_00)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/genesis.json ${CMAKE_CURRENT_BINARY_DIR}/etc/eosio/node_00/genesis.json COPYONLY)
include(installer)
include(doxygen)
# - Try to find WASM
# TODO: Check if compiler is able to generate wasm32
if ("${WASM_ROOT}" STREQUAL "")
if (APPLE)
set( WASM_ROOT "/usr/local/wasm" )
elseif (UNIX AND NOT APPLE)
set( WASM_ROOT "$ENV{HOME}/opt/wasm" )
else()
message(FATAL_ERROR "WASM not found and don't know where to look, please specify WASM_ROOT")
endif()
endif()
find_program(WASM_CLANG clang PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH)
find_program(WASM_LLC llc PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH)
find_program(WASM_LLVM_LINK llvm-link PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH)
......
# Fix directory permissions after installation of header files (primarily).
macro(install_directory_permissions)
cmake_parse_arguments(ARG "" "DIRECTORY" "" ${ARGN})
set(dir ${ARG_DIRECTORY})
install(DIRECTORY DESTINATION ${dir}
DIRECTORY_PERMISSIONS OWNER_READ
OWNER_WRITE
OWNER_EXECUTE
GROUP_READ
GROUP_EXECUTE
WORLD_READ
WORLD_EXECUTE
)
endmacro(install_directory_permissions)
include(InstallRequiredSystemLibraries)
#install_directory_permissions( DIRECTORY usr/${CMAKE_INSTALL_INCLUDEDIR}/eosio )
set(CPACK_PACKAGE_CONTACT "support@block.one")
set(CPACK_OUTPUT_FILE_PREFIX ${CMAKE_BINARY_DIR}/packages)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install)
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install)
endif()
SET(CPACK_PACKAGE_DIRECTORY "${CMAKE_INSTALL_PREFIX}")
SET(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/install")
set(CPACK_PACKAGE_NAME "EOS.IO")
set(CPACK_PACKAGE_VENDOR "block.one")
set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_PACKAGE_DESCRIPTION "A client for the EOS.IO network")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A client for the EOS.IO network")
set(CPACK_PACKAGE_DESCRIPTION "Software for the EOS.IO network")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Software for the EOS.IO network")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "EOS.IO ${CPACK_PACKAGE_VERSION}")
if(WIN32)
set(CPACK_GENERATOR "ZIP;NSIS")
set(CPACK_NSIS_EXECUTABLES_DIRECTORY .)
set(CPACK_NSIS_PACKAGE_NAME "EOS.IO v${CPACK_PACKAGE_VERSION}")
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_NSIS_PACKAGE_NAME}")
set(CPACK_NSIS_DEFINES " !define MUI_STARTMENUPAGE_DEFAULTFOLDER \\\"EOS.IO\\\"")
# it seems like windows zip files usually don't have a single directory inside them, unix tgz frequently do
SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_GENERATOR "ZIP;NSIS")
set(CPACK_NSIS_EXECUTABLES_DIRECTORY .)
set(CPACK_NSIS_PACKAGE_NAME "EOS.IO v${CPACK_PACKAGE_VERSION}")
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_NSIS_PACKAGE_NAME}")
set(CPACK_NSIS_DEFINES " !define MUI_STARTMENUPAGE_DEFAULTFOLDER \\\"EOS.IO\\\"")
# windows zip files usually don't have a single directory inside them, unix tgz usually do
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
elseif(APPLE)
set(CPACK_GENERATOR "DragNDrop")
else()
# Linux gets a .tgz
SET(CPACK_GENERATOR "TGZ;DEB")
SET(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 1)
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_RELEASE 0)
if(CMAKE_VERSION VERSION_GREATER 3.6.0) # Buggy in 3.5, behaves like VERSION_GREATER_EQUAL
set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
else()
string(TOLOWER ${CPACK_PACKAGE_NAME} CPACK_DEBIAN_PACKAGE_NAME)
execute_process(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE)
SET(CPACK_PACKAGE_FILE_NAME ${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-${CPACK_DEBIAN_PACKAGE_RELEASE}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE})
endif()
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY TRUE)
set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/EOSIO/eos")
endif()
include(CPack)
......@@ -54,7 +54,7 @@ macro(compile_wast)
endif()
set(WASM_COMMAND ${WASM_CLANG} -emit-llvm -O3 ${STDFLAG} --target=wasm32 -ffreestanding
-nostdlib -nostdlibinc -fno-threadsafe-statics -fno-rtti -fno-exceptions
-nostdlib -nostdlibinc -fno-threadsafe-statics -fno-rtti -fno-exceptions
-c ${infile} -o ${outfile}.bc
)
if (${ARG_NOWARNINGS})
......@@ -111,6 +111,8 @@ macro(add_wast_library)
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
)
#TODO: Fix this path on pending cmake install changes
install(FILES ${${ARG_TARGET}_BC_FILENAME} DESTINATION usr/share/eosio/contractsdk/lib)
endmacro(add_wast_library)
......@@ -188,4 +190,7 @@ macro(add_wast_executable)
set(extra_target_dependency)
add_test(NAME "validate_${target}_abi"
COMMAND ${CMAKE_BINARY_DIR}/scripts/abi_is_json.py ${ABI_FILES})
endmacro(add_wast_executable)
......@@ -30,42 +30,48 @@ RUN wget https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.
&& cd boost_1_64_0 \
&& ./bootstrap.sh --prefix=/usr/local \
&& echo 'using clang : 4.0 : clang++-4.0 ;' >> project-config.jam \
&& ./b2 -d0 -j4 --with-thread --with-date_time --with-system --with-filesystem --with-program_options \
&& ./b2 -d0 -j$(nproc) --with-thread --with-date_time --with-system --with-filesystem --with-program_options \
--with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine --with-iostreams toolset=clang link=static install \
&& cd .. && rm -rf boost_1_64_0
&& cd - && rm -rf boost_1_64_0
RUN wget https://github.com/mongodb/mongo-c-driver/releases/download/1.8.0/mongo-c-driver-1.8.0.tar.gz -O - | tar -xz \
&& cd mongo-c-driver-1.8.0 \
RUN wget https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz -O - | tar -xz \
&& cd mongo-c-driver-1.9.3 \
&& ./configure --disable-automatic-init-and-cleanup --prefix=/usr/local \
&& make install \
&& cd .. && rm -rf mongo-c-driver-1.8.0
&& make -j$(nproc) install \
&& cd - && rm -rf mongo-c-driver-1.9.3
RUN git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git \
&& git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git llvm/tools/clang \
&& cd llvm \
&& cmake -H. -Bbuild -GNinja -DCMAKE_INSTALL_PREFIX=/opt/wasm -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release \
&& cmake --build build --target install \
&& cd .. && rm -rf llvm
&& cd - && rm -rf llvm
RUN wget https://github.com/WebAssembly/binaryen/archive/1.37.21.tar.gz -O - | tar -xz \
&& cd binaryen-1.37.21 \
&& cmake -H. -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release \
&& cmake --build build --target install \
&& cd .. && rm -rf binaryen-1.37.21
&& cd - && rm -rf binaryen-1.37.21
RUN git clone --depth 1 git://github.com/cryptonomex/secp256k1-zkp \
&& cd secp256k1-zkp \
&& ./autogen.sh \
&& ./configure --prefix=/usr/local \
&& make install \
&& cd .. && rm -rf secp256k1-zkp
&& make -j$(nproc) install \
&& cd - && rm -rf secp256k1-zkp
RUN git clone --depth 1 -b releases/stable git://github.com/mongodb/mongo-cxx-driver \
&& cd mongo-cxx-driver \
&& cmake -H. -Bbuild -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local\
&& cmake --build build --target install
&& cmake --build build --target install && cd - && rm -rf mongo-cxx-driver
RUN git clone --depth 1 --single-branch --branch master https://github.com/ucb-bar/berkeley-softfloat-3.git \
&& cd berkeley-softfloat-3/build/Linux-x86_64-GCC \
&& make -j${nproc} SPECIALIZE_TYPE="8086-SSE" SOFTFLOAT_OPS="-DSOFTFLOAT_ROUND_EVEN -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 -DSOFTFLOAT_FAST_DIV64TO32" \
&& mkdir -p /opt/berkeley-softfloat-3 && cp softfloat.a /opt/berkeley-softfloat-3/libsoftfloat.a \
&& mv ../../source/include /opt/berkeley-softfloat-3/include && cd - && rm -rf berkeley-softfloat-3
ENV SOFTFLOAT_ROOT /opt/berkeley-softfloat-3
### If you don't want to change the depedencies, you can comment out above lines and uncomnent the following line to get faster build time.
# FROM huangminghuang/eos_builder as builder
......@@ -73,18 +79,17 @@ RUN git clone --depth 1 -b releases/stable git://github.com/mongodb/mongo-cxx-dr
RUN git clone -b master --depth 1 https://github.com/EOSIO/eos.git --recursive \
&& cd eos \
&& cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/opt/eos -DSecp256k1_ROOT_DIR=/usr/local \
-DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DSecp256k1_ROOT_DIR=/usr/local \
&& cmake --build /tmp/build --target install
FROM ubuntu:16.04
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl && rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/local/lib/* /usr/local/lib/
COPY --from=builder /tmp/build/install/bin /opt/eosio/bin
COPY --from=builder /tmp/build/bin /opt/eosio/bin
COPY --from=builder /tmp/build/contracts /contracts
COPY --from=builder /eos/Docker/config.ini /eos/genesis.json /
COPY start_eosiod.sh /opt/eosio/bin/start_eosiod.sh
ENV EOSIO_ROOT=/opt/eosio
RUN chmod +x /opt/eosio/bin/start_eosiod.sh
ENV LD_LIBRARY_PATH /usr/local/lib
VOLUME /opt/eosio/bin/data-dir
......
# Track only transactions whose scopes involve the listed accounts. Default is to track all transactions.
# filter_on_accounts =
# Limits the maximum time (in milliseconds) processing a single get_transactions call.
get-transactions-time-limit = 3
# File to read Genesis State from
# genesis-json =
genesis-json = "/opt/eosio/bin/data-dir/genesis.json"
genesis-json = /opt/eosio/bin/data-dir/genesis.json
# override the initial timestamp in the Genesis State file
# genesis-timestamp =
# the location of the block log (absolute path or relative to application data dir)
block-log-dir = "blocks"
......@@ -8,9 +16,6 @@ block-log-dir = "blocks"
# Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.
# checkpoint =
# open the database in read only mode
readonly = 0
# the location of the chain shared memory files (absolute path or relative to application data dir)
shared-file-dir = "blockchain"
......@@ -20,23 +25,49 @@ shared-file-size = 8192
# The local IP and port to listen for incoming http connections.
http-server-address = 0.0.0.0:8888
# The Access-Control-Allow-Origin http value
# access-control-allow-origin = *
# Specify the Access-Control-Allow-Origin to be returned on each request.
# access-control-allow-origin =
# The Access-Control-Allow-Headers http value
# access-control-allow-headers = Content-Type
# Specify the Access-Control-Allow-Headers to be returned on each request.
# access-control-allow-headers =
# true if Access-Control-Allow-Credentials: true should be specified in http response header
# access-control-allow-credentials = true
# Specify if Access-Control-Allow-Credentials: true should be returned on each request.
access-control-allow-credentials = false
# The local IP address and port to listen for incoming connections.
# The actual host:port used to listen for incoming p2p connections.
p2p-listen-endpoint = 0.0.0.0:9876
# The IP address and port of a remote peer to sync with.
# remote-endpoint =
# An externally accessible host:port for identifying this node. Defaults to p2p-listen-endpoint.
# p2p-server-address =
# The public endpoint of a peer node to connect to. Use multiple p2p-peer-address options as needed to compose a network.
# p2p-peer-address =
# The name supplied to identify this node amongst the peers.
agent-name = "EOS Test Agent"
# True to always send full blocks, false to send block summaries
send-whole-blocks = 1
# Can be 'any' or 'producers' or 'specified' or 'none'. If 'specified', peer-key must be specified at least once. If only 'producers', peer-key is not required. 'producers' and 'specified' may be combined.
allowed-connection = any
# The public IP address and port that should be advertized to peers.
p2p-server-address = 0.0.0.0:9876
# Optional public key of peer allowed to connect. May be used multiple times.
# peer-key =
# Tuple of [PublicKey, WIF private key] (may specify multiple times)
# peer-private-key =
# Log level: one of 'all', 'debug', 'info', 'warn', 'error', or 'off'
log-level-net-plugin = info
# Maximum number of clients from which connections are accepted, use 0 for no limit
max-clients = 25
# number of seconds to wait before cleaning up dead connections
connection-cleanup-period = 30
# True to require exact match of peer network version.
network-version-match = 0
# Enable block production, even if the chain is stale.
enable-stale-production = true
......@@ -44,36 +75,21 @@ enable-stale-production = true
# Percent of producers (0-99) that must be participating in order to produce blocks
required-participation = false
# ID of producer controlled by this node (e.g. "inita", quotes are required, may specify multiple times)
# ID of producer controlled by this node (e.g. inita; may specify multiple times)
# producer-name =
producer-name = inita
producer-name = initb
producer-name = initc
producer-name = initd
producer-name = inite
producer-name = initf
producer-name = initg
producer-name = inith
producer-name = initi
producer-name = initj
producer-name = initk
producer-name = initl
producer-name = initm
producer-name = initn
producer-name = inito
producer-name = initp
producer-name = initq
producer-name = initr
producer-name = inits
producer-name = initt
producer-name = initu
# Tuple of [public key, WIF private key] (may specify multiple times)
private-key = ["EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]
# Plugin(s) to enable, may be specified multiple times
# plugin =
# Plugin(s) to enable, may be specified multiple times
plugin = eosio::producer_plugin
plugin = eosio::chain_api_plugin
plugin = eosio::wallet_api_plugin
plugin = eosio::account_history_api_plugin
plugin = eosio::http_plugin
# plugin = eosio::mongo_db_plugin
# Enable block production with the testnet producers
producer-name = eosio
......@@ -16,7 +16,7 @@ services:
walletd:
image: eosio/eos
command: /opt/eosio/bin/eosio-walletd
command: /opt/eosio/bin/eosiowd
links:
- eosiod
volumes:
......@@ -24,4 +24,4 @@ services:
volumes:
eosiod-data-volume:
walletd-data-volume:
\ No newline at end of file
walletd-data-volume:
......@@ -46,6 +46,14 @@ pipeline {
ctest --output-on-failure
'''
}
post {
failure {
archiveArtifacts 'build/genesis.json'
archiveArtifacts 'build/tn_data_00/config.ini'
archiveArtifacts 'build/tn_data_00/stderr.txt'
archiveArtifacts 'build/test_walletd_output.log'
}
}
}
stage('MacOS') {
agent { label 'MacOS' }
......@@ -59,6 +67,14 @@ pipeline {
ctest --output-on-failure
'''
}
post {
failure {
archiveArtifacts 'build/genesis.json'
archiveArtifacts 'build/tn_data_00/config.ini'
archiveArtifacts 'build/tn_data_00/stderr.txt'
archiveArtifacts 'build/test_walletd_output.log'
}
}
}
stage('Fedora') {
agent { label 'Fedora' }
......@@ -72,6 +88,14 @@ pipeline {
ctest --output-on-failure
'''
}
post {
failure {
archiveArtifacts 'build/genesis.json'
archiveArtifacts 'build/tn_data_00/config.ini'
archiveArtifacts 'build/tn_data_00/stderr.txt'
archiveArtifacts 'build/test_walletd_output.log'
}
}
}
}
}
......
......@@ -15,9 +15,11 @@ The public testnet described in the [wiki](https://github.com/EOSIO/eos/wiki/Tes
### Supported Operating Systems
EOS.IO currently supports the following operating systems:
1. Amazon 2017.09 and higher.
2. Fedora 25 and higher (Fedora 27 recommended).
3. Ubuntu 16.04 and higher (Ubuntu 16.10 recommended).
4. MacOS Darwin 10.12 and higher (MacOS 10.13.x recommended).
2. Centos 7.
3. Fedora 25 and higher (Fedora 27 recommended).
4. Mint 18.
5. Ubuntu 16.04 (Ubuntu 16.10 recommended).
6. MacOS Darwin 10.12 and higher (MacOS 10.13.x recommended).
# Resources
1. [EOS.IO Website](https://eos.io)
......@@ -34,8 +36,8 @@ EOS.IO currently supports the following operating systems:
1. [Getting Started](#gettingstarted)
2. [Setting up a build/development environment](#setup)
1. [Automated build script](#autobuild)
1. [Clean install Linux (Amazon, Fedora, & Ubuntu) for a local testnet](#autoubuntulocal)
2. [Clean install Linux (Amazon, Fedora, & Ubuntu) for the public testnet](#autoubuntupublic)
1. [Clean install Linux (Amazon, Centos, Fedora, Mint, & Ubuntu) for a local testnet](#autoubuntulocal)
2. [Clean install Linux (Amazon, Centos, Fedora, Mint, & Ubuntu) for the public testnet](#autoubuntupublic)
3. [MacOS for a local testnet](#automaclocal)
4. [MacOS for the public testnet](#automacpublic)
3. [Building EOS and running a node](#runanode)
......@@ -56,9 +58,11 @@ EOS.IO currently supports the following operating systems:
8. [Running EOS in Docker](#docker)
9. [Manual installation of the dependencies](#manualdep)
1. [Clean install Amazon 2017.09 and higher](#manualdepamazon)
2. [Clean install Fedora 25 and higher](#manualdepfedora)
3. [Clean install Ubuntu 16.04 and higher](#manualdepubuntu)
4. [Clean install MacOS Sierra 10.12 and higher](#manualdepmacos)
2. [Clean install Centos 7 and higher](#manualdepcentos)
3. [Clean install Fedora 25 and higher](#manualdepfedora)
4. [Clean install Mint 18](#manualdepubuntu)
4. [Clean install Ubuntu 16](#manualdepubuntu)
5. [Clean install MacOS Sierra 10.12 and higher](#manualdepmacos)
<a name="gettingstarted"></a>
## Getting Started
......@@ -72,11 +76,13 @@ The following instructions detail the process of getting the software, building
Supported Operating Systems:
1. Amazon 2017.09 and higher.
2. Fedora 25 and higher (Fedora 27 recommended).
3. Ubuntu 16.04 and higher (Ubuntu 16.10 recommended).
4. MacOS Darwin 10.12 and higher (MacOS 10.13.x recommended).
2. Centos 7.
3. Fedora 25 and higher (Fedora 27 recommended).
4. Mint 18.
5. Ubuntu 16.04 (Ubuntu 16.10 recommended).
6. MacOS Darwin 10.12 and higher (MacOS 10.13.x recommended).
For Amazon, Fedora, Ubuntu & MacOS there is an automated build script that can install all dependencies and builds EOS.
For Amazon, Centos, Fedora, Mint, Ubuntu, & MacOS there is an automated build script that can install all dependencies and builds EOS.
We are working on supporting other Linux/Unix distributions in future releases.
Choose whether you will be building for a local testnet or for the public testnet and jump to the appropriate section below. Clone the EOS repository recursively as described and run eosio_build.sh located in the root `eos` folder.
......@@ -86,7 +92,7 @@ Choose whether you will be building for a local testnet or for the public testne
We strongly recommend following the instructions for building the public testnet version for [Ubuntu](#autoubuntupublic) or [Mac OS X](#automacpublic). `master` is in pieces on the garage floor while we rebuild this hotrod. This notice will be removed when `master` is usable again. Your patience is appreciated.
<a name="autoubuntulocal"></a>
#### :no_entry: Clean install Linux (Amazon, Fedora & Ubuntu) for a local testnet :no_entry:
#### :no_entry: Clean install Linux (Amazon, Centos, Fedora, Mint, & Ubuntu) for a local testnet :no_entry:
```bash
git clone https://github.com/eosio/eos --recursive
......@@ -104,7 +110,7 @@ sudo make install
Now you can proceed to the next step - [Creating and launching a single-node testnet](#singlenode)
<a name="autoubuntupublic"></a>
#### Clean install Linux (Amazon, Fedora & Ubuntu) for the public testnet
#### Clean install Linux (Amazon, Centos, Fedora, Mint, & Ubuntu) for the public testnet
```bash
git clone https://github.com/eosio/eos --recursive
......@@ -259,6 +265,7 @@ plugin = eosio::http_plugin
```
Now it should be possible to run `eosiod` and see it begin producing blocks.
You can specify the location of a custom `config.ini` by passing the `--config-dir` argument to `eosiod`.
When running `eosiod` you should get log messages similar to below. It means the blocks are successfully produced.
......@@ -299,7 +306,7 @@ cd ~/eos/build/programs/eosioc/
./eosioc wallet create # Outputs a password that you need to save to be able to lock/unlock the wallet
```
For the purpose of this walkthrough, import the private key of the `inita` account, a test account included within genesis.json, so that you're able to issue API commands under authority of an existing account. The private key referenced below is found within your `config.ini` and is provided to you for testing purposes.
For the purpose of this walkthrough, import the private key of the `eosio` account, a system account included within genesis.json, so that you're able to issue API commands under authority of an existing account. The private key referenced below is found within your `config.ini` and is provided to you for testing purposes.
```bash
./eosioc wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
......@@ -326,10 +333,10 @@ Public key: EOSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
**Important:**
Save the values for future reference.
Run the `create` command where `inita` is the account authorizing the creation of the `currency` account and `PUBLIC_KEY_1` and `PUBLIC_KEY_2` are the values generated by the `create key` command
Run the `create` command where `eosio` is the account authorizing the creation of the `currency` account and `PUBLIC_KEY_1` and `PUBLIC_KEY_2` are the values generated by the `create key` command
```bash
./eosioc create account inita currency PUBLIC_KEY_1 PUBLIC_KEY_2
./eosioc create account eosio currency PUBLIC_KEY_1 PUBLIC_KEY_2
```
You should then get a JSON response back with a transaction ID confirming it was executed successfully.
......@@ -412,10 +419,10 @@ Next verify the currency contract has the proper initial balance:
Anyone can send any message to any contract at any time, but the contracts may reject messages which are not given necessary permission. Messages are not sent "from" anyone, they are sent "with permission of" one or more accounts and permission levels. The following commands show a "transfer" message being sent to the "currency" contract.
The content of the message is `'{"from":"currency","to":"inita","quantity":"20.0000 CUR","memo":"any string"}'`. In this case we are asking the currency contract to transfer funds from itself to someone else. This requires the permission of the currency contract.
The content of the message is `'{"from":"currency","to":"eosio","quantity":"20.0000 CUR","memo":"any string"}'`. In this case we are asking the currency contract to transfer funds from itself to someone else. This requires the permission of the currency contract.
```bash
./eosioc push action currency transfer '{"from":"currency","to":"inita","quantity":"20.0000 CUR","memo":"my first transfer"}' --permission currency@active
./eosioc push action currency transfer '{"from":"currency","to":"eosio","quantity":"20.0000 CUR","memo":"my first transfer"}' --permission currency@active
```
Below is a generalization that shows the `currency` account is only referenced once, to specify which contract to deliver the `transfer` message to.
......@@ -432,7 +439,7 @@ As confirmation of a successfully submitted transaction, you will receive JSON o
So now check the state of both of the accounts involved in the previous transaction.
```bash
./eosioc get table inita currency account
./eosioc get table eosio currency account
{
"rows": [{
"currency": 1381319428,
......@@ -452,7 +459,7 @@ So now check the state of both of the accounts involved in the previous transact
}
```
As expected, the receiving account **inita** now has a balance of **20** tokens, and the sending account now has **20** less tokens than its initial supply.
As expected, the receiving account **eosio** now has a balance of **20** tokens, and the sending account now has **20** less tokens than its initial supply.
<a name="localtestnet"></a>
## Running multi-node local testnet
......@@ -559,7 +566,6 @@ Dependencies:
* OpenSSL
* LLVM 4.0
* [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git)
* [binaryen](https://github.com/WebAssembly/binaryen.git)
<a name="manualdepamazon"></a>
### Clean install Amazon 2017.09 and higher
......@@ -575,6 +581,20 @@ sudo yum install git gcc72.x86_64 gcc72-c++.x86_64 autoconf automake libtool mak
```
Install CMake 3.10.2:
```bash
cd ~
curl -L -O https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz
tar xf cmake-3.10.2.tar.gz
rm -f cmake-3.10.2.tar.gz
ln -s cmake-3.10.2/ cmake
cd cmake
./bootstrap
make
sudo make install
```
Install Boost 1.66:
```bash
......@@ -600,22 +620,79 @@ make -j$( nproc )
sudo make install
```
To use the WASM compiler, EOS has an external dependency on [binaryen](https://github.com/WebAssembly/binaryen.git):
By default LLVM and clang do not include the WASM build target, so you will have to build it yourself:
```bash
cd ~
git clone https://github.com/WebAssembly/binaryen.git
cd ~/binaryen
git checkout tags/1.37.14
cmake . && make
mkdir ~/wasm-compiler
cd ~/wasm-compiler
git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git
cd llvm/tools
git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git
cd ..
mkdir build
cd build
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=.. -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../
make -j$( nproc )
make install
```
Your environment is set up. Now you can <a href="#runanode">build EOS and run a node</a>.
<a name="manualdepcentos"></a>
### Clean install Centos 7 and higher
Install the development toolkit:
* Installation on Centos requires installing/enabling the Centos Software Collections
Repository.
[Centos SCL](https://wiki.centos.org/AdditionalResources/Repositories/SCL):
```bash
sudo yum --enablerepo=extras install centos-release-scl
sudo yum update
sudo yum install -y devtoolset-7
scl enable devtoolset-7 bash
sudo yum install git autoconf automake libtool make bzip2 \
bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 \
ocaml.x86_64 doxygen libicu-devel.x86_64 python27-devel.x86_64 \
gettext-devel.x86_64
```
Install CMake 3.10.2:
```bash
cd ~
curl -L -O https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz
tar xf cmake-3.10.2.tar.gz
cd cmake-3.10.2
./bootstrap
make -j$( nproc )
sudo make install
```
Add `BINARYEN_ROOT` to your .bash_profile:
Install Boost 1.66:
```bash
echo "export BINARYEN_ROOT=~/binaryen" >> ~/.bash_profile
cd ~
curl -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2 > boost_1.66.0.tar.bz2
tar xf boost_1.66.0.tar.bz2
echo "export BOOST_ROOT=$HOME/boost_1_66_0" >> ~/.bash_profile
source ~/.bash_profile
cd boost_1_66_0/
./bootstrap.sh "--prefix=$BOOST_ROOT"
./b2 install
```
Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git):
```bash
cd ~
git clone https://github.com/cryptonomex/secp256k1-zkp.git
cd secp256k1-zkp
./autogen.sh
./configure
make -j$( nproc )
sudo make install
```
By default LLVM and clang do not include the WASM build target, so you will have to build it yourself:
......@@ -644,9 +721,9 @@ Install the development toolkit:
```bash
sudo yum update
sudo yum install git gcc.x86_64 gcc-c++.x86_64 autoconf automake libtool make cmake.x86_64 \
bzip2 bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 \
libstdc++-devel.x86_64 python3-devel.x86_64 libedit.x86_64 \
ncurses-devel.x86_64 swig.x86_64 gettext-devel.x86_64
bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 \
libstdc++-devel.x86_64 python3-devel.x86_64 libedit.x86_64 \
ncurses-devel.x86_64 swig.x86_64 gettext-devel.x86_64
```
......@@ -675,24 +752,6 @@ make -j$( nproc )
sudo make install
```
To use the WASM compiler, EOS has an external dependency on [binaryen](https://github.com/WebAssembly/binaryen.git):
```bash
cd ~
git clone https://github.com/WebAssembly/binaryen.git
cd ~/binaryen
git checkout tags/1.37.14
cmake . && make
```
Add `BINARYEN_ROOT` to your .bash_profile:
```bash
echo "export BINARYEN_ROOT=~/binaryen" >> ~/.bash_profile
source ~/.bash_profile
```
By default LLVM and clang do not include the WASM build target, so you will have to build it yourself:
```bash
......@@ -711,7 +770,7 @@ make -j$( nproc ) install
Your environment is set up. Now you can <a href="#runanode">build EOS and run a node</a>.
<a name="manualdepubuntu"></a>
### Clean install Ubuntu 16.04 & Higher
### Clean install Ubuntu 16.04 & Linux Mint 18
Install the development toolkit:
......@@ -722,7 +781,7 @@ sudo apt-get install clang-4.0 lldb-4.0 libclang-4.0-dev cmake make \
libbz2-dev libssl-dev libgmp3-dev \
autotools-dev build-essential \
libbz2-dev libicu-dev python-dev \
autoconf libtool git
autoconf libtool git mongodb
```
Install Boost 1.66:
......@@ -739,6 +798,22 @@ source ~/.bash_profile
source ~/.bash_profile
```
Install MongoDB C++ driver:
```bash
cd ~
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
tar xf mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
make -j$( nproc )
sudo make install
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
sudo make -j$( nproc )
```
Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git):
```bash
......@@ -751,24 +826,6 @@ make
sudo make install
```
To use the WASM compiler, EOS has an external dependency on [binaryen](https://github.com/WebAssembly/binaryen.git):
```bash
cd ~
git clone https://github.com/WebAssembly/binaryen.git
cd ~/binaryen
git checkout tags/1.37.14
cmake . && make
```
Add `BINARYEN_ROOT` to your .bash_profile:
```bash
echo "export BINARYEN_ROOT=~/binaryen" >> ~/.bash_profile
source ~/.bash_profile
```
By default LLVM and clang do not include the WASM build target, so you will have to build it yourself:
```bash
......@@ -793,6 +850,7 @@ macOS additional Dependencies:
* Brew
* Newest XCode
* MongoDB C++ driver
Upgrade your XCode to the newest version:
......@@ -810,9 +868,33 @@ Install the dependencies:
```bash
brew update
brew install git automake libtool boost openssl llvm@4 gmp ninja gettext
brew install git automake libtool cmake boost openssl@1.0 llvm@4 gmp ninja gettext mongodb
brew link gettext --force
```
Install [mongo-cxx-driver (release/stable)](https://github.com/mongodb/mongo-cxx-driver):
```bash
cd ~
brew install --force pkgconfig
brew unlink pkgconfig && brew link --force pkgconfig
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
tar xf mongo-c-driver-1.9.3.tar.gz
rm -f mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=darwin --disable-automatic-init-and-cleanup --prefix=/usr/local
make -j$( sysctl -in machdep.cpu.core_count )
sudo make install
cd ..
rm -rf mongo-c-driver-1.9.3
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j$( sysctl -in machdep.cpu.core_count )
sudo make install
cd ..
rm -rf mongo-cxx-driver
```
Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git):
......@@ -826,23 +908,6 @@ make -j$( sysctl -in machdep.cpu.core_count )
sudo make install
```
Install [binaryen v1.37.14](https://github.com/WebAssembly/binaryen.git):
```bash
cd ~
git clone https://github.com/WebAssembly/binaryen.git
cd ~/binaryen
git checkout tags/1.37.14
cmake . && make -j$( sysctl -in machdep.cpu.core_count )
```
Add `BINARYEN_ROOT` to your .bash_profile:
```bash
echo "export BINARYEN_ROOT=~/binaryen" >> ~/.bash_profile
source ~/.bash_profile
```
Build LLVM and clang for WASM:
```bash
......
......@@ -29,7 +29,20 @@ add_subdirectory(simpledb)
add_subdirectory(test.system)
add_subdirectory(noop)
install( DIRECTORY eosiolib DESTINATION include/ )
install( DIRECTORY musl DESTINATION include/ )
install( DIRECTORY libc++ DESTINATION include/ )
install( DIRECTORY skeleton DESTINATION share/ )
file(GLOB SKELETONS RELATIVE ${CMAKE_SOURCE_DIR}/contracts "skeleton/*")
# Documented multiple output support is broken, so properly setting up the multiple
# dependencies in the custom target is not possible. (CMake 3.5)
add_custom_command(OUTPUT share/eosio/skeleton/skeleton.cpp
COMMAND ${CMAKE_COMMAND} -E make_directory ../share/eosio/skeleton
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/skeleton ../share/eosio/skeleton
DEPENDS ${SKELETONS}
COMMENT Copying skeleton contract...
VERBATIM)
add_custom_target(copy_skeleton_contract ALL DEPENDS share/eosio/skeleton/skeleton.cpp)
install(DIRECTORY eosiolib DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR})
install(DIRECTORY musl DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR})
install(DIRECTORY libc++ DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR})
install(DIRECTORY skeleton DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/eosio)
install_directory_permissions(DIRECTORY ${CMAKE_INSTALL_FULL_DATAROOTDIR}/eosio)
......@@ -29,7 +29,7 @@ extern "C" {
}
// maybe assert?
eosio_assert(def->condition, def->message);
eosio_assert((uint32_t)def->condition, def->message);
} else if( action == N(provereset) ) {
eosio_assert(global_variable == 45, "Global Variable Initialized poorly");
global_variable = 100;
......
......@@ -14,3 +14,5 @@ extern "C" {
bancor::example_converter::apply( c, a );
}
}
}
......@@ -14,11 +14,22 @@
{"name":"memo", "type":"string"}
]
},{
"name": "create",
"base": "",
"fields": [
{"name":"issuer", "type":"account_name"},
{"name":"maximum_supply", "type":"asset"},
{"name":"can_freeze", "type":"uint8"},
{"name":"can_recall", "type":"uint8"},
{"name":"can_whitelist", "type":"uint8"}
]
},{
"name": "issue",
"base": "",
"fields": [
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"asset"}
{"name":"quantity", "type":"asset"},
{"name":"memo", "type":"string"}
]
},{
"name": "account",
......@@ -42,7 +53,11 @@
},{
"name": "issue",
"type": "issue"
}, {
"name": "create",
"type": "create"
}
],
"tables": [{
"name": "account",
......@@ -58,4 +73,4 @@
"key_types" : ["uint64"]
}
]
}
\ No newline at end of file
}
......@@ -3,11 +3,11 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <currency/currency.hpp> /// defines transfer struct (abi)
#include <eosiolib/currency.hpp>
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
currency::contract::apply( code, action );
eosio::currency().apply( code, action );
}
}
......@@ -4,11 +4,4 @@
*/
#include <eosiolib/eosio.hpp>
#include <eosiolib/token.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/generic_currency.hpp>
namespace currency {
typedef eosio::generic_currency< eosio::token<N(currency),S(4,CUR)> > contract;
}
......@@ -34,7 +34,7 @@ Indicates that a particular account wishes to become a producer
Storage changes will be billed to 'account'
## eosio.system::unstake account quantity
- **account** - the account which is requsting their balance be unstaked
- **account** - the account which is requesting their balance be unstaked
- **quantity** - the quantity which will be unstaked, unstaked tokens lose voting influence immediately
- in order to unstake tokens, an account must request them. The user will receive them over
......@@ -71,7 +71,7 @@ Indicates that a particular account wishes to become a producer
- this special action is triggered when a block is applied by the given producer and cannot be generated from
any other source. It is used to pay producers and calculate missed blocks of other producers.
- producer pay is deposited into the prodcer's stake balance and can be withdrawn over time.
- producer pay is deposited into the producer's stake balance and can be withdrawn over time.
- if blocknum is the start of a new round this may update the active producer config from the producer votes.
......
......@@ -163,6 +163,9 @@ namespace eosiosystem {
currency::inline_transfer(cr.owner, SystemAccount, rewards, "producer claiming rewards");
}
static void on( const finishundel& ) {
}
static void apply( account_name code, action_name act ) {
if ( !eosio::dispatch<currency, typename currency::transfer, typename currency::issue>( code, act ) ) {
......@@ -182,8 +185,7 @@ namespace eosiosystem {
}
}
} /// apply
} /// apply
};
} /// eosiosystem
} /// eosiosystem
......@@ -102,6 +102,7 @@ extern "C" {
* @param name - name of the account to be verified
*/
void require_auth( account_name name );
bool has_auth( account_name name );
/**
* Get the account which specifies the code that is being run
......
......@@ -122,6 +122,18 @@ namespace eosio {
data = pack(value);
}
/**
* @tparam Action - a type derived from action_meta<Scope,Name>
* @param value - will be serialized via pack into data
*/
template<typename Action>
action( const permission_level& auth, account_name a, action_name n, const Action& value )
:authorization(1,auth) {
account = a;
name = n;
data = pack(value);
}
EOSLIB_SERIALIZE( action, (account)(name)(authorization)(data) )
void send() const {
......
#pragma once
#include <eosiolib/serialize.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/system.h>
#include <tuple>
#include <limits>
namespace eosio {
......@@ -23,34 +28,125 @@ namespace eosio {
typedef uint64_t symbol_name;
static constexpr bool is_valid_symbol( symbol_name sym ) {
sym >>= 8;
for( int i = 0; i < 7; ++i ) {
char c = (char)(sym & 0xff);
if( !('A' <= c && c <= 'Z') ) return false;
sym >>= 8;
if( !(sym & 0xff) ) {
do {
sym >>= 8;
if( (sym & 0xff) ) return false;
++i;
} while( i < 7 );
}
}
return true;
}
static constexpr uint32_t symbol_name_length( symbol_name tmp ) {
tmp >>= 8; /// skip precision
uint32_t length = 0;
while( tmp & 0xff && length <= 7) {
++length;
tmp >>= 8;
}
return length;
}
struct symbol_type {
symbol_type( symbol_name v = S(4,EOS) ):value(v){}
symbol_name value;
bool is_valid()const { return is_valid_symbol( value ); }
uint64_t precision()const { return value & 0xff; }
uint64_t name()const { return value >> 8; }
uint32_t name_length()const { return symbol_name_length( value ); }
operator symbol_name()const { return value; }
void print(bool show_precision=true)const {
if( show_precision ){
::eosio::print(precision());
prints(",");
}
auto sym = value;
sym >>= 8;
for( int i = 0; i < 7; ++i ) {
char c = (char)(sym & 0xff);
if( !c ) return;
prints_l(&c, 1 );
sym >>= 8;
}
}
EOSLIB_SERIALIZE( symbol_type, (value) )
};
struct extended_symbol : public symbol_type
{
extended_symbol( symbol_name s = 0, account_name c = 0 ):symbol_type(s),contract(c){}
account_name contract;
void print()const {
symbol_type::print();
prints("@");
printn( contract );
}
friend bool operator == ( const extended_symbol& a, const extended_symbol& b ) {
return std::tie( a.value, a.contract ) == std::tie( b.value, b.contract );
}
friend bool operator != ( const extended_symbol& a, const extended_symbol& b ) {
return std::tie( a.value, a.contract ) != std::tie( b.value, b.contract );
}
EOSLIB_SERIALIZE( extended_symbol, (value)(contract) )
};
struct asset {
int64_t amount = 0;
symbol_name symbol = S(4,EOS);
symbol_type symbol = S(4,EOS);
static constexpr int64_t max_amount = (1LL << 62) - 1;
explicit asset( int64_t a = 0, uint64_t s = S(4,EOS))
:amount(a),symbol(s){}
explicit asset( int64_t a = 0, symbol_name s = S(4,EOS))
:amount(a),symbol(s)
{
eosio_assert( is_amount_within_range(), "magnitude of asset amount must be less than 2^62" );
eosio_assert( symbol.is_valid(), "invalid symbol name" );
}
bool is_amount_within_range()const { return -max_amount <= amount && amount <= max_amount; }
bool is_valid()const { return is_amount_within_range() && symbol.is_valid(); }
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const asset& t ){
return ds << t.amount << t.symbol;
void set_amount( int64_t a ) {
amount = a;
eosio_assert( is_amount_within_range(), "magnitude of asset amount must be less than 2^62" );
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, asset& t ){
return ds >> t.amount >> t.symbol;
asset operator-()const {
asset r = *this;
r.amount = -r.amount;
return r;
}
asset& operator-=( const asset& a ) {
eosio_assert( a.symbol == symbol, "attempt to subtract asset with different symbol" );
eosio_assert( amount >= a.amount, "integer underflow subtracting asset balance" );
amount -= a.amount;
eosio_assert( -max_amount <= amount, "subtraction underflow" );
eosio_assert( amount <= max_amount, "subtraction overflow" );
return *this;
}
asset& operator+=( const asset& a ) {
eosio_assert( a.symbol == symbol, "attempt to add asset with different symbol" );
eosio_assert( amount + a.amount >= a.amount, "integer overflow adding asset balance" );
amount += a.amount;
eosio_assert( -max_amount <= amount, "addition underflow" );
eosio_assert( amount <= max_amount, "addition overflow" );
return *this;
}
......@@ -67,7 +163,9 @@ namespace eosio {
}
asset& operator*=( int64_t a ) {
eosio_assert( a == 0 || (amount * a) / a == amount, "integer overflow multiplying asset balance" );
eosio_assert( a == 0 || (amount * a) / a == amount, "multiplication overflow or underflow" );
eosio_assert( -max_amount <= amount, "multiplication underflow" );
eosio_assert( amount <= max_amount, "multiplication overflow" );
amount *= a;
return *this;
}
......@@ -128,6 +226,65 @@ namespace eosio {
eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount >= b.amount;
}
void print()const {
int64_t p = (int64_t)symbol.precision();
int64_t p10 = 1;
while( p > 0 ) {
p10 *= 10; --p;
}
p = (int64_t)symbol.precision();
char fraction[p+1];
fraction[p] = '\0';
auto change = amount % p10;
for( int64_t i = p -1; i >= 0; --i ) {
fraction[i] = (change % 10) + '0';
change /= 10;
}
printi( amount / p10 );
prints(".");
prints_l( fraction, uint32_t(p) );
prints(" ");
symbol.print(false);
}
EOSLIB_SERIALIZE( asset, (amount)(symbol) )
};
struct extended_asset : public asset {
account_name contract = N(eosio.token);
extended_symbol get_extended_symbol()const { return extended_symbol( symbol, contract ); }
extended_asset(){}
extended_asset( int64_t v, extended_symbol s ):asset(v,s),contract(s.contract){}
extended_asset( asset a, account_name c ):asset(a),contract(c){}
void print()const {
asset::print();
prints("@");
printn(contract);
}
extended_asset operator-()const {
asset r = this->asset::operator-();
return {r, contract};
}
friend extended_asset operator - ( const extended_asset& a, const extended_asset& b ) {
eosio_assert( a.contract == b.contract, "type mismatch" );
asset r = static_cast<const asset&>(a) - static_cast<const asset&>(b);
return {r, a.contract};
}
friend extended_asset operator + ( const extended_asset& a, const extended_asset& b ) {
eosio_assert( a.contract == b.contract, "type mismatch" );
asset r = static_cast<const asset&>(a) + static_cast<const asset&>(b);
return {r, a.contract};
}
EOSLIB_SERIALIZE( extended_asset, (amount)(symbol)(contract) )
};
} /// namespace eosio
} /// namespace eosio
......@@ -46,6 +46,27 @@ extern "C" {
void __ashlti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift);
void __ashrti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift);
void __addtf3( long double& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
void __subtf3( long double& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
void __multf3( long double& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
void __divtf3( long double& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
int __eqtf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
int __netf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
int __getf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
int __gttf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
int __letf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
int __lttf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
int __cmptf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
int __unordtf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb );
void __extendsftf2( long double& ret, float f );
void __extenddftf2( long double& ret, double f );
int64_t __fixtfdi( uint64_t l, uint64_t h );
int32_t __fixtfsi( uint64_t l, uint64_t h );
uint64_t __fixunstfdi( uint64_t l, uint64_t h );
uint32_t __fixunstfsi( uint64_t l, uint64_t h );
double __trunctfdf2( uint64_t l, uint64_t h );
float __trunctfsf2( uint64_t l, uint64_t h );
void __break_point();
} // extern "C"
#include <eosiolib/eosio.hpp>
#include <eosiolib/asset.hpp>
#include <eosiolib/multi_index.hpp>
namespace eosio {
using std::string;
using std::array;
/**
* This contract enables the creation, issuance, and transfering of many different tokens.
*
*/
class currency {
public:
currency( account_name contract = current_receiver() )
:_contract(contract)
{ }
struct create {
account_name issuer;
asset maximum_supply;
// array<char,32> issuer_agreement_hash;
uint8_t issuer_can_freeze = true;
uint8_t issuer_can_recall = true;
uint8_t issuer_can_whitelist = true;
/*(issuer_agreement_hash)*/
EOSLIB_SERIALIZE( create, (issuer)(maximum_supply)(issuer_can_freeze)(issuer_can_recall)(issuer_can_whitelist) )
};
struct transfer
{
account_name from;
account_name to;
asset quantity;
string memo;
EOSLIB_SERIALIZE( transfer, (from)(to)(quantity)(memo) )
};
struct issue {
account_name to;
asset quantity;
string memo;
EOSLIB_SERIALIZE( issue, (to)(quantity)(memo) )
};
struct fee_schedule {
uint64_t primary_key()const { return 0; }
array<extended_asset,7> fee_per_length;
EOSLIB_SERIALIZE( fee_schedule, (fee_per_length) )
};
struct account {
asset balance;
bool frozen = false;
bool whitelist = true;
uint64_t primary_key()const { return balance.symbol; }
EOSLIB_SERIALIZE( account, (balance)(frozen)(whitelist) )
};
struct currency_stats {
asset supply;
asset max_supply;
account_name issuer;
bool can_freeze = true;
bool can_recall = true;
bool can_whitelist = true;
bool is_frozen = false;
bool enforce_whitelist = false;
uint64_t primary_key()const { return supply.symbol.name(); }
EOSLIB_SERIALIZE( currency_stats, (supply)(max_supply)(issuer)(can_freeze)(can_recall)(can_whitelist)(is_frozen)(enforce_whitelist) )
};
typedef eosio::multi_index<N(accounts), account> accounts;
typedef eosio::multi_index<N(stat), currency_stats> stats;
asset get_balance( account_name owner, symbol_name symbol )const {
accounts t( _contract, owner );
return t.get(symbol).balance;
}
asset get_supply( symbol_name symbol )const {
accounts t( _contract, symbol );
return t.get(symbol).balance;
}
static void inline_transfer( account_name from, account_name to, extended_asset amount, string memo = string(), permission_name perm = N(active) ) {
action act( permission_level( from, perm ), amount.contract, N(transfer), transfer{from,to,amount,memo} );
act.send();
}
void inline_transfer( account_name from, account_name to, asset amount, string memo = string(), permission_name perm = N(active) ) {
action act( permission_level( from, perm ), _contract, N(transfer), transfer{from,to,amount,memo} );
act.send();
}
bool apply( account_name contract, action_name act ) {
if( contract != _contract )
return false;
switch( act ) {
case N(issue):
print( "issue\n");
on( unpack_action<issue>() );
return true;
case N(transfer):
print( "transfer\n");
on( unpack_action<transfer>() );
return true;
case N(create):
print( "create\n");
on( unpack_action<create>() );
return true;
}
return false;
}
/**
* This is factored out so it can be used as a building block
*/
void create_currency( const create& c ) {
auto sym = c.maximum_supply.symbol;
eosio_assert( sym.is_valid(), "invalid symbol name" );
stats statstable( _contract, sym.name() );
auto existing = statstable.find( sym.name() );
eosio_assert( existing == statstable.end(), "token with symbol already exists" );
statstable.emplace( c.issuer, [&]( auto& s ) {
s.supply.symbol = c.maximum_supply.symbol;
s.max_supply = c.maximum_supply;
s.issuer = c.issuer;
s.can_freeze = c.issuer_can_freeze;
s.can_recall = c.issuer_can_recall;
s.can_whitelist = c.issuer_can_whitelist;
});
}
void issue_currency( const issue& i ) {
auto sym = i.quantity.symbol.name();
stats statstable( _contract, sym );
const auto& st = statstable.get( sym );
statstable.modify( st, 0, [&]( auto& s ) {
s.supply.amount += i.quantity.amount;
eosio_assert( s.supply.amount >= 0, "underflow" );
});
add_balance( st.issuer, i.quantity, st, st.issuer );
}
void on( const create& c ) {
require_auth( c.issuer );
create_currency( c );
/*
auto fee = get_fee_schedule()[c.maximum_supply.name_length()];
if( fee.amount > 0 ) {
inline_transfer( c.issuer, _contract, fee, "symbol registration fee" );
}
*/
}
void on( const issue& i ) {
auto sym = i.quantity.symbol.name();
stats statstable( _contract, sym );
const auto& st = statstable.get( sym );
require_auth( st.issuer );
eosio_assert( i.quantity.is_valid(), "invalid quantity" );
eosio_assert( i.quantity.amount > 0, "must issue positive quantity" );
statstable.modify( st, 0, [&]( auto& s ) {
s.supply.amount += i.quantity.amount;
});
add_balance( st.issuer, i.quantity, st, st.issuer );
if( i.to != st.issuer )
{
inline_transfer( st.issuer, i.to, i.quantity, i.memo );
}
}
void on( const transfer& t ) {
auto sym = t.quantity.symbol.name();
stats statstable( _contract, sym );
const auto& st = statstable.get( sym );
require_recipient( t.to );
eosio_assert( t.quantity.is_valid(), "invalid quantity" );
eosio_assert( t.quantity.amount > 0, "must transfer positive quantity" );
sub_balance( t.from, t.quantity, st );
add_balance( t.to, t.quantity, st, t.from );
}
private:
void sub_balance( account_name owner, asset value, const currency_stats& st ) {
accounts from_acnts( _contract, owner );
const auto& from = from_acnts.get( value.symbol );
eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" );
if( has_auth( owner ) ) {
eosio_assert( !st.can_freeze || !from.frozen, "account is frozen by issuer" );
eosio_assert( !st.can_freeze || !st.is_frozen, "all transfers are frozen by issuer" );
eosio_assert( !st.enforce_whitelist || from.whitelist, "account is not white listed" );
} else if( has_auth( st.issuer ) ) {
eosio_assert( st.can_recall, "issuer may not recall token" );
} else {
eosio_assert( false, "insufficient authority" );
}
from_acnts.modify( from, owner, [&]( auto& a ) {
a.balance.amount -= value.amount;
});
}
void add_balance( account_name owner, asset value, const currency_stats& st, account_name ram_payer )
{
accounts to_acnts( _contract, owner );
auto to = to_acnts.find( value.symbol );
if( to == to_acnts.end() ) {
eosio_assert( !st.enforce_whitelist, "can only transfer to white listed accounts" );
to_acnts.emplace( ram_payer, [&]( auto& a ){
a.balance = value;
});
} else {
eosio_assert( !st.enforce_whitelist || to->whitelist, "receiver requires whitelist by issuer" );
to_acnts.modify( to, 0, [&]( auto& a ) {
a.balance.amount += value.amount;
});
}
}
private:
account_name _contract;
};
}
......@@ -6,7 +6,9 @@
#include <eosiolib/system.h>
#include <eosiolib/memory.h>
#include <eosiolib/vector.hpp>
#include <boost/container/flat_map.hpp>
#include <eosiolib/varint.hpp>
#include <array>
#include <string>
......@@ -154,6 +156,7 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, key256& d) {
return ds;
}
/**
* Serialize a uint128_t into a stream
* @brief Serialize a uint128_t
......@@ -289,10 +292,11 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, int64_t& d) {
* @param d value to serialize
*/
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const uint64_t d) {
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const uint64_t& d) {
ds.write( (const char*)&d, sizeof(d) );
return ds;
}
/**
* Deserialize a uint64_t from a stream
* @brief Deserialize a uint64_t
......@@ -305,6 +309,18 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, uint64_t& d) {
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const double& d) {
ds.write( (const char*)&d, sizeof(d) );
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, double& d) {
ds.read((char*)&d, sizeof(d) );
return ds;
}
/**
* Serialize a int16_t into a stream
* @brief Serialize a int16_t
......@@ -415,6 +431,42 @@ DataStream& operator >> ( DataStream& ds, std::string& v ) {
return ds;
}
template<typename DataStream, typename T, std::size_t N>
DataStream& operator << ( DataStream& ds, const std::array<T,N>& v ) {
for( const auto& i : v )
ds << i;
return ds;
}
template<typename DataStream, typename T, std::size_t N>
DataStream& operator >> ( DataStream& ds, std::array<T,N>& v ) {
for( auto& i : v )
ds >> i;
return ds;
}
template<typename DataStream, typename K, typename V>
DataStream& operator<<( DataStream& ds, const boost::container::flat_map<K,V>& m ) {
ds << unsigned_int( m.size() );
for( const auto& i : m )
ds << i.first << i.second;
return ds;
}
template<typename DataStream, typename K, typename V>
DataStream& operator>>( DataStream& ds, boost::container::flat_map<K,V>& m ) {
m.clear();
unsigned_int s; ds >> s;
for( uint32_t i = 0; i < s.value; ++i ) {
K k; V v;
ds >> k >> v;
m.emplace( std::move(k), std::move(v) );
}
return ds;
}
template<typename DataStream, typename T>
DataStream& operator << ( DataStream& ds, const vector<T>& v ) {
ds << unsigned_int( v.size() );
......
......@@ -1069,4 +1069,15 @@ int32_t db_idx256_lowerbound(account_name code, account_name scope, table_name t
int32_t db_idx256_upperbound(account_name code, account_name scope, table_name table, void* data, uint32_t data_len, uint64_t* primary);
int32_t db_idx256_end(account_name code, account_name scope, table_name table);
int32_t db_idx_double_store(account_name scope, table_name table, account_name payer, uint64_t id, const uint64_t* secondary);
void db_idx_double_update(int32_t iterator, account_name payer, const uint64_t* secondary);
void db_idx_double_remove(int32_t iterator);
int32_t db_idx_double_next(int32_t iterator, uint64_t* primary);
int32_t db_idx_double_previous(int32_t iterator, uint64_t* primary);
int32_t db_idx_double_find_primary(account_name code, account_name scope, table_name table, uint64_t* secondary, uint64_t primary);
int32_t db_idx_double_find_secondary(account_name code, account_name scope, table_name table, const uint64_t* secondary, uint64_t* primary);
int32_t db_idx_double_lowerbound(account_name code, account_name scope, table_name table, uint64_t* secondary, uint64_t* primary);
int32_t db_idx_double_upperbound(account_name code, account_name scope, table_name table, uint64_t* secondary, uint64_t* primary);
int32_t db_idx_double_end(account_name code, account_name scope, table_name table);
}
......@@ -40,6 +40,37 @@ namespace eosio {
template<bool... bs>
using all_true = std::is_same< bool_pack<bs..., true>, bool_pack<true, bs...> >;
template<typename Word, size_t NumWords>
static void set_from_word_sequence(const std::array<Word, NumWords>& arr, fixed_key<Size>& key)
{
auto itr = key._data.begin();
word_t temp_word = 0;
const size_t sub_word_shift = 8 * sizeof(Word);
const size_t num_sub_words = sizeof(word_t) / sizeof(Word);
auto sub_words_left = num_sub_words;
for( auto&& w : arr ) {
if( sub_words_left > 1 ) {
temp_word |= static_cast<word_t>(w);
temp_word <<= sub_word_shift;
--sub_words_left;
continue;
}
eosio_assert( sub_words_left == 1, "unexpected error in fixed_key constructor" );
temp_word |= static_cast<word_t>(w);
sub_words_left = num_sub_words;
*itr = temp_word;
temp_word = 0;
++itr;
}
if( sub_words_left != num_sub_words ) {
if( sub_words_left > 1 )
temp_word <<= 8 * (sub_words_left-1);
*itr = temp_word;
}
}
public:
typedef uint128_t word_t;
......@@ -54,17 +85,6 @@ namespace eosio {
*/
fixed_key() : _data() {}
/**
* @brief Constructor to fixed_key object from array of num_words() words
*
* @details Constructor to fixed_key object from array of num_words() words
* @param arr data
*/
fixed_key(const word_t (&arr)[num_words()])
{
std::copy(arr, arr + num_words(), _data.begin());
}
/**
* @brief Constructor to fixed_key object from std::array of num_words() words
*
......@@ -76,6 +96,19 @@ namespace eosio {
std::copy(arr.begin(), arr.end(), _data.begin());
}
template<typename Word, size_t NumWords,
typename Enable = typename std::enable_if<std::is_integral<Word>::value &&
!std::is_same<Word, bool>::value &&
sizeof(Word) < sizeof(word_t)>::type >
fixed_key(const std::array<Word, NumWords>& arr)
{
static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(Word)) * sizeof(Word),
"size of the backing word size is not divisible by the size of the array element" );
static_assert( sizeof(Word) * NumWords <= Size, "too many words supplied to fixed_key constructor" );
set_from_word_sequence(arr, *this);
}
template<typename FirstWord, typename... Rest>
static
fixed_key<Size>
......@@ -87,38 +120,11 @@ namespace eosio {
Rest... rest)
{
static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(FirstWord)) * sizeof(FirstWord),
"size of the backing word size is not divisble by the size of the words supplied as arguments" );
static_assert( sizeof(FirstWord) * (1 + sizeof...(Rest)) <= Size, "too many words supplied to fixed_key constructor" );
"size of the backing word size is not divisible by the size of the words supplied as arguments" );
static_assert( sizeof(FirstWord) * (1 + sizeof...(Rest)) <= Size, "too many words supplied to make_from_word_sequence" );
fixed_key<Size> key;
auto itr = key._data.begin();
word_t temp_word = 0;
const size_t sub_word_shift = 8 * sizeof(FirstWord);
const size_t num_sub_words = sizeof(word_t) / sizeof(FirstWord);
auto sub_words_left = num_sub_words;
for( auto&& w : { first_word, rest... } ) {
if( sub_words_left > 1 ) {
temp_word |= static_cast<word_t>(w);
temp_word <<= sub_word_shift;
--sub_words_left;
continue;
}
eosio_assert( sub_words_left == 1, "unexpected error in fixed_key constructor" );
temp_word |= static_cast<word_t>(w);
sub_words_left = num_sub_words;
*itr = temp_word;
temp_word = 0;
++itr;
}
if( sub_words_left != num_sub_words ) {
if( sub_words_left > 1 )
temp_word <<= 8 * (sub_words_left-1);
*itr = temp_word;
}
set_from_word_sequence(std::array<FirstWord, 1+sizeof...(Rest)>{{ first_word, rest... }}, key);
return key;
}
......
......@@ -147,11 +147,11 @@ ope * fixed_point128<3> b(a);
*/
uint128_t frac_part() const {
if(!Q) return 0;
return val << (32-Q);
return uint128_t(val << (32-Q));
}
void print() const {
uint128_t ip(int_part());
uint128_t ip((uint128_t)int_part());
uint128_t fp(frac_part());
printi128(&ip);
prints(".");
......@@ -230,7 +230,7 @@ ope * fixed_point128<3> b(a);
*/
uint64_t frac_part() const {
if(!Q) return 0;
return val << (32-Q);
return uint64_t(val << (32-Q));
}
void print() const {
......@@ -306,7 +306,7 @@ ope * fixed_point128<3> b(a);
}
uint32_t frac_part() const {
if(!Q) return 0;
return val << (32-Q);
return uint32_t(val << (32-Q));
}
void print() const {
......@@ -576,7 +576,7 @@ ope * fixed_point128<3> b(a);
{
eosio_assert( rhs != 0, "divide by zero" );
fixed_point64<Q> result = fixed_point32<0>(lhs) / fixed_point32<0>(rhs);
fixed_point64<Q> result = fixed_point32<0>((int32_t)lhs) / fixed_point32<0>((int32_t)rhs);
return result;
}
......@@ -595,7 +595,7 @@ ope * fixed_point128<3> b(a);
{
eosio_assert( rhs != 0, "divide by zero" );
fixed_point128<Q> result = fixed_point64<0>(lhs) / fixed_point64<0>(rhs);
fixed_point128<Q> result = fixed_point64<0>((int32_t)lhs) / fixed_point64<0>((int32_t)rhs);
return fixed_point128<Q>(result);
}
......
......@@ -61,21 +61,21 @@ namespace eosio {
};
struct account {
uint64_t symbol = token_type::symbol;
token_type balance;
uint64_t symbol = token_type::symbol;
auto primary_key() const { return symbol; }
EOSLIB_SERIALIZE( account, (symbol)(balance) )
EOSLIB_SERIALIZE( account, (balance)(symbol) )
};
struct currency_stats {
uint64_t symbol = token_type::symbol;
token_type supply;
uint64_t symbol = token_type::symbol;
auto primary_key() const { return symbol; }
EOSLIB_SERIALIZE( currency_stats, (symbol)(supply) )
EOSLIB_SERIALIZE( currency_stats, (supply)(symbol) )
};
/**
......@@ -87,8 +87,8 @@ namespace eosio {
static token_type get_balance( account_name owner ) {
accounts t( code, owner );
auto ptr = t.find( symbol );
return ptr ? ptr->balance : token_type( asset(0, symbol) );
auto itr = t.find( symbol );
return itr != t.end() ? itr->balance : token_type( asset(0, symbol) );
}
static void set_balance( account_name owner, token_type balance, account_name create_bill_to, account_name update_bill_to ) {
......@@ -97,9 +97,9 @@ namespace eosio {
acc.symbol = symbol;
acc.balance = balance;
};
auto ptr = t.find( symbol );
if (ptr) {
t.update( *ptr, update_bill_to, f);
auto itr = t.find( symbol );
if( itr != t.end() ) {
t.modify( itr, update_bill_to, f);
} else {
t.emplace( create_bill_to, f);
}
......@@ -109,16 +109,16 @@ namespace eosio {
require_auth( code );
stats t( code, code );
auto ptr = t.find( symbol );
if (ptr) {
t.update(*ptr, 0, [&](currency_stats& s) { s.supply += act.quantity; });
auto itr = t.find( symbol );
if( itr != t.end() ) {
t.modify(itr, 0, [&](currency_stats& s) { s.supply += act.quantity; });
} else {
t.emplace(code, [&](currency_stats& s) { s.supply = act.quantity; });
}
set_balance( code, get_balance( code ) + act.quantity, code, 0 );
set_balance( code, get_balance( code ) + token_type(act.quantity), code, 0 );
inline_transfer( code, act.to, act.quantity );
inline_transfer( code, act.to, act.quantity );
}
......@@ -126,11 +126,11 @@ namespace eosio {
require_auth( act.from );
require_recipient(act.to,act.from);
set_balance( act.from, get_balance( act.from ) - act.quantity, act.from, act.from );
set_balance( act.to, get_balance( act.to ) + act.quantity, act.from, 0 );
set_balance( act.from, get_balance( act.from ) - token_type(act.quantity), act.from, act.from );
set_balance( act.to, get_balance( act.to ) + token_type(act.quantity), act.from, 0 );
}
static void inline_transfer( account_name from, account_name to, token_type quantity,
static void inline_transfer( account_name from, account_name to, token_type quantity,
string memo = string() )
{
action act( permission_level(from,N(active)), transfer_memo( from, to, asset(quantity), move(memo) ));
......@@ -155,6 +155,3 @@ namespace eosio {
};
} /// namespace eosio
此差异已折叠。
......@@ -58,7 +58,8 @@ extern "C" {
* printi(1e+18); // Output: 1000000000000000000
* @endcode
*/
void printi( uint64_t value );
void printi( int64_t value );
void printui( uint64_t value );
/**
* Prints value as a 128 bit unsigned integer
......@@ -80,11 +81,12 @@ extern "C" {
*
* Example:
* @code
* uint64_t double_value = double_div( i64_to_double(5), i64_to_double(10) );
* printd(double_value); // Output: 0.5
* double double_value = 5.0 / 10.0;
* printd(*(uint64_t*)(&double_value)); // Output: 0.5
* @endcode
*/
void printd(uint64_t value);
void printd(double value);
void printdi(int64_t value);
/**
* Prints a 64 bit names as base32 encoded string
......
/**
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
......@@ -28,8 +28,12 @@ namespace eosio {
* @param num to be printed
*/
inline void print( uint64_t num ) {
printui(num);
}
inline void print( int64_t num ) {
printi(num);
}
inline void print( double d ) { printdi( *((int64_t*)&d) ); }
/**
* Prints 32 bit unsigned integer as a 64 bit unsigned integer
......@@ -46,7 +50,7 @@ namespace eosio {
* @param num to be printed
*/
inline void print( int num ) {
printi(uint64_t(num));
printi(num);
}
inline void print( long num ) {
......@@ -106,6 +110,7 @@ namespace eosio {
prints(val?"true":"false");
}
template<typename T>
inline void print( T&& t ) {
t.print();
......
......@@ -30,7 +30,7 @@ namespace eosio {
* @brief Constructor to double object from uint64 value
*
* @details Constructor to double object from uint64 value
* @param val data
* @param _val data
*/
real(const uint64_t &_val) : val(_val) {}
......
......@@ -35,29 +35,29 @@ namespace eosio {
static T get( scope_name scope = Code ) {
table t( Code, scope );
auto ptr = t.find( pk_value );
eosio_assert( bool(ptr), "singleton does not exist" );
return ptr->value;
auto itr = t.find( pk_value );
eosio_assert( itr != t.end(), "singleton does not exist" );
return itr->value;
}
static T get_or_default( scope_name scope = Code, const T& def = T() ) {
table t( Code, scope );
auto ptr = t.find( pk_value );
return ptr ? ptr->value : def;
auto itr = t.find( pk_value );
return itr != t.end() ? itr->value : def;
}
static T get_or_create( scope_name scope = Code, const T& def = T() ) {
table t( Code, scope );
auto ptr = t.find( pk_value );
return ptr ? ptr->value
auto itr = t.find( pk_value );
return itr != t.end() ? itr->value
: t.emplace(BillToAccount, [&](row& r) { r.value = def; });
}
static void set( const T& value = T(), scope_name scope = Code, account_name b = BillToAccount ) {
table t( Code, scope );
auto ptr = t.find( pk_value );
if (ptr) {
t.update(*ptr, b, [&](row& r) { r.value = value; });
auto itr = t.find( pk_value );
if( itr != t.end() ) {
t.modify(itr, b, [&](row& r) { r.value = value; });
} else {
t.emplace(b, [&](row& r) { r.value = value; });
}
......@@ -65,9 +65,9 @@ namespace eosio {
static void remove( scope_name scope = Code ) {
table t( Code, scope );
auto ptr = t.find( pk_value );
if (ptr) {
t.remove(*ptr);
auto itr = t.find( pk_value );
if( itr != t.end() ) {
t.erase(itr);
}
}
};
......
......@@ -46,9 +46,9 @@ namespace eosio {
template<typename Base, typename Quote>
friend price<Base,Quote> operator / ( const Base& b, const Quote& q );
explicit operator asset()const { return asset( static_cast<int64_t>(quantity), Symbol ); }
operator asset()const { return asset( int64_t(quantity), Symbol ); }
token( const asset& a ):quantity(static_cast<uint64_t>(a.amount)) {
token( const asset& a ):quantity(NumberType(a.amount)) {
eosio_assert( a.symbol == Symbol, "attempt to construct token from asset with different symbol" );
eosio_assert( 0 <= a.amount, "attemt to convert asset with negative value to token" );
}
......
......@@ -6,3 +6,8 @@ add_wast_executable(TARGET exchange
)
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_dependencies( exchange currency )
add_executable(test_exchange test_exchange.cpp )
#bfp/lib/pack.c bfp/lib/posit.cpp bfp/lib/util.c bfp/lib/op2.c)
target_link_libraries( test_exchange fc )
target_include_directories( test_exchange PUBLIC fixed_point/include )
......@@ -4,71 +4,160 @@
"type": "name"
}
],
"structs": [{
"name": "order_id",
"structs": [
{
"name": "extended_symbol",
"base": "",
"fields": [
{"name":"name", "type":"account_name"},
{"name":"id", "type":"uint64"}
{"name":"sym", "type":"symbol"},
{"name":"contract", "type":"account_name"}
]
},{
"name" : "bid",
},
{
"name": "extended_asset",
"base": "",
"fields" : [
{"name":"buyer", "type":"order_id"},
{"name":"at_price", "type":"uint128"},
{"name":"quantity", "type":"uint64"},
{"name":"expiration", "type":"time"}
"fields": [
{"name":"quantity", "type":"asset"},
{"name":"contract", "type":"account_name"}
]
},{
"name" : "ask",
},
{
"name": "upmargin",
"base": "",
"fields" : [
{"name":"seller", "type":"order_id"},
{"name":"at_price", "type":"uint128"},
{"name":"quantity", "type":"uint64"},
{"name":"expiration", "type":"time"}
"fields": [
{"name":"borrower", "type":"account_name"},
{"name":"market", "type":"symbol"},
{"name":"delta_borrow", "type":"extended_asset"},
{"name":"delta_collateral", "type":"extended_asset"}
]
},{
"name" : "account",
},
{
"name": "covermargin",
"base": "",
"fields" : [
{"name":"owner", "type":"account_name"},
{"name":"eos_balance", "type":"uint64"},
{"name":"currency_balance", "type":"uint64"},
{"name":"open_orders", "type":"uint32"}
"fields": [
{"name":"borrower", "type":"account_name"},
{"name":"market", "type":"symbol"},
{"name":"cover_amount", "type":"extended_asset"}
]
},{
"name" : "buy_order",
"base" : "bid",
"fields" : [
{"name":"fill_or_kill", "type":"uint8"}
},
{
"name": "lend",
"base": "",
"fields": [
{"name":"lender", "type":"account_name"},
{"name":"market", "type":"symbol"},
{"name":"quantity", "type":"extended_asset"}
]
},
{
"name": "unlend",
"base": "",
"fields": [
{"name":"lender", "type":"account_name"},
{"name":"market", "type":"symbol"},
{"name":"interest_shares", "type":"float64"},
{"name":"interest_symbol", "type":"extended_symbol"}
]
},
{
"name": "trade",
"base": "",
"fields": [
{"name":"seller", "type":"account_name"},
{"name":"market", "type":"symbol"},
{"name":"sell", "type":"extended_asset"},
{"name":"min_receive", "type":"extended_asset"},
{"name":"expire", "type":"uint32"},
{"name":"fill_or_kill", "type":"uint8"}
]
},
{
"name": "createx",
"base": "",
"fields": [
{"name":"creator", "type":"account_name"},
{"name":"initial_supply", "type":"asset"},
{"name":"fee", "type":"uint32"},
{"name":"base_deposit", "type":"extended_asset"},
{"name":"quote_deposit", "type":"extended_asset"}
]
},
{
"name": "transfer",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"asset"},
{"name":"memo", "type":"string"}
]
},
{
"name": "deposit",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"quantity", "type":"extended_asset"}
]
},
{
"name": "create",
"base": "",
"fields": [
{"name":"issuer", "type":"account_name"},
{"name":"maximum_supply", "type":"asset"},
{"name":"can_freeze", "type":"uint8"},
{"name":"can_recall", "type":"uint8"},
{"name":"can_whitelist", "type":"uint8"}
]
},{
"name": "issue",
"base": "",
"fields": [
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"asset"},
{"name":"memo", "type":"string"}
]
},{
"name": "account",
"base": "",
"fields": [
{"name":"currency", "type":"uint64"},
{"name":"balance", "type":"uint64"}
]
},{
"name" : "sell_order",
"base" : "ask",
"fields" : [
{"name":"fill_or_kill", "type":"uint8"}
"name": "currency_stats",
"base": "",
"fields": [
{"name":"currency", "type":"uint64"},
{"name":"supply", "type":"uint64"}
]
}
],
"actions": [{
"name": "buy",
"type": "buy_order"
},{
"name": "sell",
"type": "sell_order"
},{
"name": "cancelbuy",
"type": "order_id"
"actions": [
{ "name": "deposit", "type": "deposit" },
{ "name": "transfer", "type": "transfer" },
{ "name": "trade", "type": "trade" },
{ "name": "createx", "type": "createx" },
{ "name": "issue", "type": "issue" },
{ "name": "lend", "type": "lend" },
{ "name": "unlend", "type": "unlend" },
{ "name": "upmargin", "type": "upmargin" },
{ "name": "covermargin", "type": "covermargin" },
{ "name": "create", "type": "create" }
],
"tables": [{
"name": "account",
"type": "account",
"index_type": "i64",
"key_names" : ["currency"],
"key_types" : ["uint64"]
},{
"name": "cancelsell",
"type": "order_id"
"name": "stat",
"type": "currency_stats",
"index_type": "i64",
"key_names" : ["currency"],
"key_types" : ["uint64"]
}
],
"tables": [
{"table":"bids","type":"bid"},
{"table":"asks","type":"ask"},
{"table":"account","type":"account"}
]
}
\ No newline at end of file
}
#include <math.h>
#include "exchange.hpp"
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t act ) {
typedef eosio::generic_currency< eosio::token<N(eosio.system),S(4,EOS)> > eos;
typedef eosio::generic_currency< eosio::token<N(currency),S(4,CUR)> > cur;
#include "exchange_state.cpp"
#include "exchange_accounts.cpp"
#include "market_state.cpp"
namespace eosio {
void exchange::on( const deposit& d ) {
eosio_assert( d.quantity.is_valid(), "invalid quantity" );
currency::inline_transfer( d.from, _this_contract, d.quantity, "deposit" );
_accounts.adjust_balance( d.from, d.quantity, "deposit" );
}
void exchange::on( const withdraw& w ) {
require_auth( w.from );
eosio_assert( w.quantity.is_valid(), "invalid quantity" );
eosio_assert( w.quantity.amount >= 0, "cannot withdraw negative balance" ); // Redundant? inline_transfer will fail if w.quantity is not positive.
_accounts.adjust_balance( w.from, -w.quantity );
currency::inline_transfer( _this_contract, w.from, w.quantity, "withdraw" );
}
void exchange::on( const trade& t ) {
require_auth( t.seller );
eosio_assert( t.sell.is_valid(), "invalid sell amount" );
eosio_assert( t.sell.amount > 0, "sell amount must be positive" );
eosio_assert( t.min_receive.is_valid(), "invalid min receive amount" );
eosio_assert( t.min_receive.amount >= 0, "min receive amount cannot be negative" );
auto receive_symbol = t.min_receive.get_extended_symbol();
eosio_assert( t.sell.get_extended_symbol() != receive_symbol, "invalid conversion" );
market_state market( _this_contract, t.market, _accounts );
auto temp = market.exstate;
auto output = temp.convert( t.sell, receive_symbol );
while( temp.requires_margin_call() ) {
market.margin_call( receive_symbol );
temp = market.exstate;
output = temp.convert( t.sell, receive_symbol );
}
market.exstate = temp;
print( name(t.seller), " ", t.sell, " => ", output, "\n" );
if( t.min_receive.amount != 0 ) {
eosio_assert( t.min_receive.amount <= output.amount, "unable to fill" );
}
_accounts.adjust_balance( t.seller, -t.sell, "sold" );
_accounts.adjust_balance( t.seller, output, "received" );
if( market.exstate.supply.amount != market.initial_state().supply.amount ) {
auto delta = market.exstate.supply - market.initial_state().supply;
_excurrencies.issue_currency( { .to = _this_contract,
.quantity = delta,
.memo = string("") } );
}
/// TODO: if pending order start deferred trx to fill it
market.save();
}
/**
* This action shall fail if it would result in a margin call
*/
void exchange::on( const upmargin& b ) {
require_auth( b.borrower );
eosio_assert( b.delta_borrow.is_valid(), "invalid borrow delta" );
eosio_assert( b.delta_collateral.is_valid(), "invalid collateral delta" );
market_state market( _this_contract, b.market, _accounts );
eosio_assert( b.delta_borrow.amount != 0 || b.delta_collateral.amount != 0, "no effect" );
eosio_assert( b.delta_borrow.get_extended_symbol() != b.delta_collateral.get_extended_symbol(), "invalid args" );
eosio_assert( market.exstate.base.balance.get_extended_symbol() == b.delta_borrow.get_extended_symbol() ||
market.exstate.quote.balance.get_extended_symbol() == b.delta_borrow.get_extended_symbol(),
"invalid asset for market" );
eosio_assert( market.exstate.base.balance.get_extended_symbol() == b.delta_collateral.get_extended_symbol() ||
market.exstate.quote.balance.get_extended_symbol() == b.delta_collateral.get_extended_symbol(),
"invalid asset for market" );
market.update_margin( b.borrower, b.delta_borrow, b.delta_collateral );
/// if this succeeds then the borrower will see their balances adjusted accordingly,
/// if they don't have sufficient balance to either fund the collateral or pay off the
/// debt then this will fail before we go further.
_accounts.adjust_balance( b.borrower, b.delta_borrow, "borrowed" );
_accounts.adjust_balance( b.borrower, -b.delta_collateral, "collateral" );
market.save();
}
void exchange::on( const covermargin& c ) {
require_auth( c.borrower );
eosio_assert( c.cover_amount.is_valid(), "invalid cover amount" );
eosio_assert( c.cover_amount.amount > 0, "cover amount must be positive" );
market_state market( _this_contract, c.market, _accounts );
market.cover_margin( c.borrower, c.cover_amount);
exchange<N(exchange), S(4,EXC), eos, cur>::apply( code, act );
}
market.save();
}
void exchange::on( const createx& c ) {
require_auth( c.creator );
eosio_assert( c.initial_supply.is_valid(), "invalid initial supply" );
eosio_assert( c.initial_supply.amount > 0, "initial supply must be positive" );
eosio_assert( c.base_deposit.is_valid(), "invalid base deposit" );
eosio_assert( c.base_deposit.amount > 0, "base deposit must be positive" );
eosio_assert( c.quote_deposit.is_valid(), "invalid quote deposit" );
eosio_assert( c.quote_deposit.amount > 0, "quote deposit must be positive" );
eosio_assert( c.base_deposit.get_extended_symbol() != c.quote_deposit.get_extended_symbol(),
"must exchange between two different currencies" );
print( "base: ", c.base_deposit.get_extended_symbol() );
print( "quote: ",c.quote_deposit.get_extended_symbol() );
auto exchange_symbol = c.initial_supply.symbol.name();
print( "marketid: ", exchange_symbol, " \n " );
markets exstates( _this_contract, exchange_symbol );
auto existing = exstates.find( exchange_symbol );
eosio_assert( existing == exstates.end(), "market already exists" );
exstates.emplace( c.creator, [&]( auto& s ) {
s.manager = c.creator;
s.supply = extended_asset(c.initial_supply, _this_contract);
s.base.balance = c.base_deposit;
s.quote.balance = c.quote_deposit;
s.base.peer_margin.total_lent.symbol = c.base_deposit.symbol;
s.base.peer_margin.total_lent.contract = c.base_deposit.contract;
s.base.peer_margin.total_lendable.symbol = c.base_deposit.symbol;
s.base.peer_margin.total_lendable.contract = c.base_deposit.contract;
s.quote.peer_margin.total_lent.symbol = c.quote_deposit.symbol;
s.quote.peer_margin.total_lent.contract = c.quote_deposit.contract;
s.quote.peer_margin.total_lendable.symbol = c.quote_deposit.symbol;
s.quote.peer_margin.total_lendable.contract = c.quote_deposit.contract;
});
_excurrencies.create_currency( { .issuer = _this_contract,
// TODO: After currency contract respects maximum supply limits, the maximum supply here needs to be set appropriately.
.maximum_supply = asset( 0, c.initial_supply.symbol ),
.issuer_can_freeze = false,
.issuer_can_whitelist = false,
.issuer_can_recall = false } );
_excurrencies.issue_currency( { .to = _this_contract,
.quantity = c.initial_supply,
.memo = string("initial exchange tokens") } );
_accounts.adjust_balance( c.creator, extended_asset( c.initial_supply, _this_contract ), "new exchange issue" );
_accounts.adjust_balance( c.creator, -c.base_deposit, "new exchange deposit" );
_accounts.adjust_balance( c.creator, -c.quote_deposit, "new exchange deposit" );
}
void exchange::on( const lend& w ) {
require_auth( w.lender );
eosio_assert( w.quantity.is_valid(), "invalid quantity" );
eosio_assert( w.quantity.amount > 0, "must lend a positive amount" );
market_state market( _this_contract, w.market, _accounts );
market.lend( w.lender, w.quantity );
market.save();
}
void exchange::on( const unlend& w ) {
require_auth( w.lender );
eosio_assert( w.interest_shares > 0, "must unlend a positive amount" );
market_state market( _this_contract, w.market, _accounts );
market.unlend( w.lender, w.interest_shares, w.interest_symbol );
market.save();
}
void exchange::on( const currency::transfer& t, account_name code ) {
if( code == _this_contract )
_excurrencies.on( t );
if( t.to == _this_contract ) {
auto a = extended_asset(t.quantity, code);
eosio_assert( a.is_valid(), "invalid quantity in transfer" );
eosio_assert( a.amount != 0, "zero quantity is disallowed in transfer");
eosio_assert( a.amount > 0 || t.memo == "withdraw", "withdrew tokens without withdraw in memo");
eosio_assert( a.amount < 0 || t.memo == "deposit", "received tokens without deposit in memo" );
_accounts.adjust_balance( t.from, a, t.memo );
}
}
bool exchange::apply( account_name contract, account_name act ) {
if( act == N(transfer) ) {
on( unpack_action<currency::transfer>(), contract );
return true;
}
if( contract != _this_contract )
return false;
switch( act ) {
case N(createx):
on( unpack_action<createx>() );
return true;
case N(trade):
on( unpack_action<trade>() );
return true;
case N(lend):
on( unpack_action<lend>() );
return true;
case N(unlend):
on( unpack_action<unlend>() );
return true;
case N(deposit):
on( unpack_action<deposit>() );
return true;
case N(withdraw):
on( unpack_action<withdraw>() );
return true;
case N(upmargin):
on( unpack_action<upmargin>() );
return true;
case N(covermargin):
on( unpack_action<covermargin>() );
return true;
default:
return _excurrencies.apply( contract, act );
}
}
} /// namespace eosio
extern "C" {
void apply( uint64_t code, uint64_t action ) {
eosio::exchange( current_receiver() ).apply( code, action );
}
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/generic_currency.hpp>
#include <eosiolib/multi_index.hpp>
using eosio::asset;
using eosio::symbol_name;
using eosio::indexed_by;
using eosio::const_mem_fun;
using eosio::price_ratio;
using eosio::price;
template<account_name ExchangeAccount, symbol_name ExchangeSymbol,
typename BaseCurrency, typename QuoteCurrency>
class exchange {
public:
typedef eosio::generic_currency< eosio::token<ExchangeAccount,ExchangeSymbol> > exchange_currency;
typedef typename BaseCurrency::token_type base_token_type;
typedef typename QuoteCurrency::token_type quote_token_type;
typedef typename exchange_currency::token_type ex_token_type;
struct account {
account_name owner;
base_token_type base_balance;
quote_token_type quote_balance;
uint64_t primary_key()const { return owner; }
EOSLIB_SERIALIZE( account, (owner)(base_balance)(quote_balance) )
};
typedef eosio::multi_index< N(accounts), account> account_index_type;
template<typename BaseTokenType, typename QuoteTokenType>
struct limit_order {
typedef eosio::price<BaseTokenType, QuoteTokenType> price_type;
static const uint64_t precision = (1000ll * 1000ll * 1000ll * 1000ll);
uint64_t primary;
account_name owner;
uint32_t id;
uint32_t expiration;
BaseTokenType for_sale;
price_type sell_price;
uint64_t primary_key()const { return primary; }
uint128_t by_owner_id()const { return get_owner_id( owner, id ); }
uint64_t by_expiration()const { return expiration; }
uint128_t by_price()const { return sell_price; }
static uint128_t get_price( BaseTokenType base, QuoteTokenType quote ) {
return (uint128_t( precision ) * base.quantity ) / quote.quantity;
}
static uint128_t get_owner_id( account_name owner, uint32_t id ) { return (uint128_t( owner ) << 64) | id; }
EOSLIB_SERIALIZE( limit_order, (primary)(owner)(id)(expiration)(for_sale)(sell_price) )
};
typedef limit_order<base_token_type, quote_token_type> limit_base_quote;
typedef eosio::multi_index< N(sellbq), limit_base_quote,
indexed_by< N(price), const_mem_fun<limit_base_quote, uint128_t, &limit_base_quote::by_price > >,
indexed_by< N(ownerid), const_mem_fun<limit_base_quote, uint128_t, &limit_base_quote::by_owner_id> >,
indexed_by< N(expire), const_mem_fun<limit_base_quote, uint64_t, &limit_base_quote::by_expiration> >
> limit_base_quote_index;
typedef limit_order<quote_token_type, base_token_type> limit_quote_base;
typedef eosio::multi_index< N(sellqb), limit_quote_base,
indexed_by< N(price), const_mem_fun<limit_quote_base, uint128_t, &limit_quote_base::by_price > >,
indexed_by< N(ownerid), const_mem_fun<limit_quote_base, uint128_t, &limit_quote_base::by_owner_id> >,
indexed_by< N(expire), const_mem_fun<limit_quote_base, uint64_t, &limit_quote_base::by_expiration> >
> limit_quote_base_index;
account_index_type _accounts;
limit_base_quote_index _base_quote_orders;
limit_base_quote_index _quote_base_orders;
exchange()
:_accounts( ExchangeAccount, ExchangeAccount ),
_base_quote_orders( ExchangeAccount, ExchangeAccount ),
_quote_base_orders( ExchangeAccount, ExchangeAccount )
{
}
ACTION( ExchangeAccount, deposit ) {
account_name from;
asset amount;
EOSLIB_SERIALIZE( deposit, (from)(amount) )
};
void on( const deposit& d ) {
require_auth( d.from );
const account* owner = _accounts.find( d.from );
if( !owner ) {
owner = &_accounts.emplace( d.from, [&]( auto& a ) {
a.owner = d.from;
});
}
switch( d.amount.symbol ) {
case base_token_type::symbol:
BaseCurrency::inline_transfer( d.from, ExchangeAccount, base_token_type(d.amount.amount) );
_accounts.update( *owner, 0, [&]( auto& a ) {
a.base_balance += base_token_type(d.amount);
});
break;
case quote_token_type::symbol:
QuoteCurrency::inline_transfer( d.from, ExchangeAccount, quote_token_type(d.amount.amount) );
_accounts.update( *owner, 0, [&]( auto& a ) {
a.quote_balance += quote_token_type(d.amount);
});
break;
default:
eosio_assert( false, "invalid symbol" );
}
}
ACTION( ExchangeAccount, withdraw ) {
account_name to;
asset amount;
EOSLIB_SERIALIZE( withdraw, (to)(amount) )
};
void on( const withdraw& w ) {
require_auth( w.to );
const account* owner = _accounts.find( w.to );
eosio_assert( owner != nullptr, "unknown exchange account" );
switch( w.amount.symbol ) {
case base_token_type::symbol:
eosio_assert( owner->base_balance >= base_token_type(w.amount), "insufficient balance" );
_accounts.update( *owner, 0, [&]( auto& a ) {
a.base_balance -= base_token_type(w.amount);
});
BaseCurrency::inline_transfer( ExchangeAccount, w.to, base_token_type(w.amount.amount) );
break;
case quote_token_type::symbol:
eosio_assert( owner->quote_balance >= quote_token_type(w.amount), "insufficient balance" );
_accounts.update( *owner, 0, [&]( auto& a ) {
a.quote_balance -= quote_token_type(w.amount);
});
QuoteCurrency::inline_transfer( ExchangeAccount, w.to, quote_token_type(w.amount.amount) );
break;
default:
eosio_assert( false, "invalid symbol" );
}
}
ACTION( ExchangeAccount, neworder ) {
account_name owner;
uint32_t id;
asset amount_to_sell;
bool fill_or_kill;
uint128_t sell_price;
uint32_t expiration;
EOSLIB_SERIALIZE( neworder, (owner)(id)(amount_to_sell)(fill_or_kill)(sell_price)(expiration) )
};
void on( const neworder& order ) {
require_auth( order.owner );
if( order.amount_to_sell.symbol == base_token_type::symbol ) {
_base_quote_orders.emplace( order.owner, [&]( auto& o ) {
o.primary = 0;// _base_quote_orders.next_available_id()
o.owner = order.owner;
o.id = order.id;
o.expiration = order.expiration;
o.for_sale = order.amount_to_sell;
o.sell_price = order.sell_price;
});
}
else if( order.amount_to_sell.symbol == quote_token_type::symbol ) {
_quote_base_orders.emplace( order.owner, [&]( auto& o ) {
o.primary = 0;// _base_quote_orders.next_available_id()
o.owner = order.owner;
o.id = order.id;
o.expiration = order.expiration;
o.for_sale = order.amount_to_sell;
o.sell_price = order.sell_price;
});
}
}
ACTION( ExchangeAccount, cancelorder ) {
account_name owner;
uint32_t id;
EOSLIB_SERIALIZE( cancelorder, (owner)(id) )
};
void on( const cancelorder& order ) {
require_auth( order.owner );
auto idx = _base_quote_orders.template get_index<N(ownerid)>();
auto itr = idx.find( limit_base_quote::get_owner_id( order.owner, order.id ) );
if( itr != idx.end() ) {
_base_quote_orders.remove(*itr);
}
}
static void apply( uint64_t code, uint64_t act ) {
if( !eosio::dispatch<exchange,
deposit, withdraw,
neworder, cancelorder
>( code, act ) ) {
exchange::exchange_currency::apply( code, act );
}
}
};
#include <eosiolib/currency.hpp>
#include <boost/container/flat_map.hpp>
#include <cmath>
#include <exchange/market_state.hpp>
namespace eosio {
/**
* This contract enables users to create an exchange between any pair of
* standard currency types. A new exchange is created by funding it with
* an equal value of both sides of the order book and giving the issuer
* the initial shares in that orderbook.
*
* To prevent exessive rounding errors, the initial deposit should include
* a sizeable quantity of both the base and quote currencies and the exchange
* shares should have a quantity 100x the quantity of the largest initial
* deposit.
*
* Users must deposit funds into the exchange before they can trade on the
* exchange.
*
* Each time an exchange is created a new currency for that exchanges market
* maker is also created. This currencies supply and symbol must be unique and
* it uses the currency contract's tables to manage it.
*/
class exchange {
private:
account_name _this_contract;
currency _excurrencies;
exchange_accounts _accounts;
public:
exchange( account_name self )
:_this_contract(self),
_excurrencies(self),
_accounts(self)
{}
/**
* Create a new exchange between two extended asset types,
* creator will receive the initial supply of a new token type
*/
struct createx {
account_name creator;
asset initial_supply;
uint32_t fee;
extended_asset base_deposit;
extended_asset quote_deposit;
EOSLIB_SERIALIZE( createx, (creator)(initial_supply)(fee)(base_deposit)(quote_deposit) )
};
struct deposit {
account_name from;
extended_asset quantity;
EOSLIB_SERIALIZE( deposit, (from)(quantity) )
};
struct withdraw {
account_name from;
extended_asset quantity;
EOSLIB_SERIALIZE( withdraw, (from)(quantity) )
};
struct lend {
account_name lender;
symbol_type market;
extended_asset quantity;
EOSLIB_SERIALIZE( lend, (lender)(market)(quantity) )
};
struct unlend {
account_name lender;
symbol_type market;
double interest_shares;
extended_symbol interest_symbol;
EOSLIB_SERIALIZE( unlend, (lender)(market)(interest_shares)(interest_symbol) )
};
struct covermargin {
account_name borrower;
symbol_type market;
extended_asset cover_amount;
EOSLIB_SERIALIZE( covermargin, (borrower)(market)(cover_amount) )
};
struct upmargin {
account_name borrower;
symbol_type market;
extended_asset delta_borrow;
extended_asset delta_collateral;
EOSLIB_SERIALIZE( upmargin, (borrower)(market)(delta_borrow)(delta_collateral) )
};
struct trade {
account_name seller;
symbol_type market;
extended_asset sell;
extended_asset min_receive;
uint32_t expire = 0;
uint8_t fill_or_kill = true;
EOSLIB_SERIALIZE( trade, (seller)(market)(sell)(min_receive)(expire)(fill_or_kill) )
};
// TODO: Need ability to cancel trades in order book.
void on( const deposit& d );
void on( const withdraw& w );
void on( const lend& w );
void on( const unlend& w );
void on( const createx& c );
void on( const trade& t );
void on( const upmargin& b );
void on( const covermargin& b );
void on( const currency::transfer& t, account_name code );
bool apply( account_name contract, account_name act );
};
}
#include <exchange/exchange_accounts.hpp>
namespace eosio {
void exchange_accounts::adjust_balance( account_name owner, extended_asset delta, const string& reason ) {
(void)reason;
auto table = exaccounts_cache.find( owner );
if( table == exaccounts_cache.end() ) {
table = exaccounts_cache.emplace( owner, exaccounts(_this_contract, owner ) ).first;
}
auto useraccounts = table->second.find( owner );
if( useraccounts == table->second.end() ) {
table->second.emplace( owner, [&]( auto& exa ){
exa.owner = owner;
exa.balances[delta.get_extended_symbol()] = delta.amount;
eosio_assert( delta.amount >= 0, "overdrawn balance 1" );
});
} else {
table->second.modify( useraccounts, 0, [&]( auto& exa ) {
const auto& b = exa.balances[delta.get_extended_symbol()] += delta.amount;
eosio_assert( b >= 0, "overdrawn balance 2" );
});
}
}
} /// namespace eosio
#pragma once
#include <eosiolib/asset.hpp>
#include <eosiolib/multi_index.hpp>
namespace eosio {
using boost::container::flat_map;
/**
* Each user has their own account with the exchange contract that keeps track
* of how much a user has on deposit for each extended asset type. The assumption
* is that storing a single flat map of all balances for a particular user will
* be more practical than breaking this down into a multi-index table sorted by
* the extended_symbol.
*/
struct exaccount {
account_name owner;
flat_map<extended_symbol, int64_t> balances;
uint64_t primary_key() const { return owner; }
EOSLIB_SERIALIZE( exaccount, (owner)(balances) )
};
typedef eosio::multi_index<N(exaccounts), exaccount> exaccounts;
/**
* Provides an abstracted interface around storing balances for users. This class
* caches tables to make multiple accesses effecient.
*/
struct exchange_accounts {
exchange_accounts( account_name code ):_this_contract(code){}
void adjust_balance( account_name owner, extended_asset delta, const string& reason = string() );
private:
account_name _this_contract;
/**
* Keep a cache of all accounts tables we access
*/
flat_map<account_name, exaccounts> exaccounts_cache;
};
} /// namespace eosio
#include <exchange/exchange_state.hpp>
namespace eosio {
extended_asset exchange_state::convert_to_exchange( connector& c, extended_asset in ) {
real_type R(supply.amount);
real_type C(c.balance.amount+in.amount);
real_type F(c.weight/1000.0);
real_type T(in.amount);
real_type ONE(1.0);
real_type E = -R * (ONE - std::pow( ONE + T / C, F) );
int64_t issued = int64_t(E);
supply.amount += issued;
c.balance.amount += in.amount;
return extended_asset( issued, supply.get_extended_symbol() );
}
extended_asset exchange_state::convert_from_exchange( connector& c, extended_asset in ) {
eosio_assert( in.contract == supply.contract, "unexpected asset contract input" );
eosio_assert( in.symbol== supply.symbol, "unexpected asset symbol input" );
real_type R(supply.amount - in.amount);
real_type C(c.balance.amount);
real_type F(1000.0/c.weight);
real_type E(in.amount);
real_type ONE(1.0);
real_type T = C * (std::pow( ONE + E/R, F) - ONE);
int64_t out = int64_t(T);
supply.amount -= in.amount;
c.balance.amount -= out;
return extended_asset( out, c.balance.get_extended_symbol() );
}
extended_asset exchange_state::convert( extended_asset from, extended_symbol to ) {
auto sell_symbol = from.get_extended_symbol();
auto ex_symbol = supply.get_extended_symbol();
auto base_symbol = base.balance.get_extended_symbol();
auto quote_symbol = quote.balance.get_extended_symbol();
if( sell_symbol != ex_symbol ) {
if( sell_symbol == base_symbol ) {
from = convert_to_exchange( base, from );
} else if( sell_symbol == quote_symbol ) {
from = convert_to_exchange( quote, from );
} else {
eosio_assert( false, "invalid sell" );
}
} else {
if( to == base_symbol ) {
from = convert_from_exchange( base, from );
} else if( to == quote_symbol ) {
from = convert_from_exchange( quote, from );
} else {
eosio_assert( false, "invalid conversion" );
}
}
if( to != from.get_extended_symbol() )
return convert( from, to );
return from;
}
bool exchange_state::requires_margin_call( const exchange_state::connector& con )const {
if( con.peer_margin.total_lent.amount > 0 ) {
auto tmp = *this;
auto base_total_col = int64_t(con.peer_margin.total_lent.amount * con.peer_margin.least_collateralized);
auto covered = tmp.convert( extended_asset( base_total_col, con.balance.get_extended_symbol()), con.peer_margin.total_lent.get_extended_symbol() );
if( covered.amount <= con.peer_margin.total_lent.amount )
return true;
}
return false;
}
bool exchange_state::requires_margin_call()const {
return requires_margin_call( base ) || requires_margin_call( quote );
}
} /// namespace eosio
#pragma once
#include <eosiolib/asset.hpp>
namespace eosio {
typedef double real_type;
struct margin_state {
extended_asset total_lendable;
extended_asset total_lent;
real_type least_collateralized = std::numeric_limits<double>::max();
/**
* Total shares allocated to those who have lent, when someone unlends they get
* total_lendable * user_interest_shares / interest_shares and total_lendable is reduced.
*
* When interest is paid, it shows up in total_lendable
*/
real_type interest_shares = 0;
real_type lend( int64_t new_lendable ) {
if( total_lendable.amount > 0 ) {
real_type new_shares = (interest_shares * new_lendable) / total_lendable.amount;
interest_shares += new_shares;
total_lendable.amount += new_lendable;
} else {
interest_shares += new_lendable;
total_lendable.amount += new_lendable;
}
return new_lendable;
}
extended_asset unlend( double ishares ) {
extended_asset result = total_lent;
print( "unlend: ", ishares, " existing interest_shares: ", interest_shares, "\n" );
result.amount = int64_t( (ishares * total_lendable.amount) / interest_shares );
total_lendable.amount -= result.amount;
interest_shares -= ishares;
eosio_assert( interest_shares >= 0, "underflow" );
eosio_assert( total_lendable.amount >= 0, "underflow" );
return result;
}
EOSLIB_SERIALIZE( margin_state, (total_lendable)(total_lent)(least_collateralized)(interest_shares) )
};
/**
* Uses Bancor math to create a 50/50 relay between two asset types. The state of the
* bancor exchange is entirely contained within this struct. There are no external
* side effects associated with using this API.
*/
struct exchange_state {
account_name manager;
extended_asset supply;
uint32_t fee = 0;
struct connector {
extended_asset balance;
uint32_t weight = 500;
margin_state peer_margin; /// peer_connector collateral lending balance
EOSLIB_SERIALIZE( connector, (balance)(weight)(peer_margin) )
};
connector base;
connector quote;
uint64_t primary_key()const { return supply.symbol.name(); }
extended_asset convert_to_exchange( connector& c, extended_asset in );
extended_asset convert_from_exchange( connector& c, extended_asset in );
extended_asset convert( extended_asset from, extended_symbol to );
bool requires_margin_call( const exchange_state::connector& con )const;
bool requires_margin_call()const;
EOSLIB_SERIALIZE( exchange_state, (manager)(supply)(fee)(base)(quote) )
};
typedef eosio::multi_index<N(markets), exchange_state> markets;
} /// namespace eosio
#include <exchange/market_state.hpp>
#include <boost/math/special_functions/relative_difference.hpp>
namespace eosio {
market_state::market_state( account_name this_contract, symbol_type market_symbol, exchange_accounts& acnts )
:marketid( market_symbol.name() ),
market_table( this_contract, marketid ),
base_margins( this_contract, (marketid<<4) + 1),
quote_margins( this_contract, (marketid<<4) + 2),
base_loans( this_contract, (marketid<<4) + 1),
quote_loans( this_contract, (marketid<<4) + 2),
_accounts(acnts),
market_state_itr( market_table.find(marketid) )
{
eosio_assert( market_state_itr != market_table.end(), "unknown market" );
exstate = *market_state_itr;
}
void market_state::margin_call( extended_symbol debt_type ) {
if( debt_type == exstate.base.balance.get_extended_symbol() )
margin_call( exstate.base, base_margins );
else
margin_call( exstate.quote, quote_margins );
}
void market_state::margin_call( exchange_state::connector& c, margins& marginstable ) {
auto price_idx = marginstable.get_index<N(callprice)>();
auto pos = price_idx.begin();
if( pos == price_idx.end() )
return;
auto receipt = exstate.convert( pos->collateral, pos->borrowed.get_extended_symbol() );
eosio_assert( receipt.amount >= pos->borrowed.amount, "programmer error: insufficient collateral to cover" );/// VERY BAD, SHOULD NOT HAPPEN
auto change_debt = receipt - pos->borrowed;
auto change_collat = exstate.convert( change_debt, pos->collateral.get_extended_symbol() );
_accounts.adjust_balance( pos->owner, change_collat );
c.peer_margin.total_lent.amount -= pos->borrowed.amount;
price_idx.erase(pos);
pos = price_idx.begin();
if( pos != price_idx.end() )
c.peer_margin.least_collateralized = pos->call_price;
else
c.peer_margin.least_collateralized = double(uint64_t(-1));
}
const exchange_state& market_state::initial_state()const {
return *market_state_itr;
}
void market_state::lend( account_name lender, const extended_asset& quantity ) {
auto sym = quantity.get_extended_symbol();
_accounts.adjust_balance( lender, -quantity );
if( sym == exstate.base.balance.get_extended_symbol() ) {
double new_shares = exstate.base.peer_margin.lend( quantity.amount );
adjust_lend_shares( lender, base_loans, new_shares );
}
else if( sym == exstate.quote.balance.get_extended_symbol() ) {
double new_shares = exstate.quote.peer_margin.lend( quantity.amount );
adjust_lend_shares( lender, quote_loans, new_shares );
}
else eosio_assert( false, "unable to lend to this market" );
}
void market_state::unlend( account_name lender, double ishares, const extended_symbol& sym ) {
eosio_assert( ishares > 0, "cannot unlend negative balance" );
adjust_lend_shares( lender, base_loans, -ishares );
print( "sym: ", sym );
if( sym == exstate.base.balance.get_extended_symbol() ) {
extended_asset unlent = exstate.base.peer_margin.unlend( ishares );
_accounts.adjust_balance( lender, unlent );
}
else if( sym == exstate.quote.balance.get_extended_symbol() ) {
extended_asset unlent = exstate.quote.peer_margin.unlend( ishares );
_accounts.adjust_balance( lender, unlent );
}
else eosio_assert( false, "unable to lend to this market" );
}
void market_state::adjust_lend_shares( account_name lender, loans& l, double delta ) {
auto existing = l.find( lender );
if( existing == l.end() ) {
l.emplace( lender, [&]( auto& obj ) {
obj.owner = lender;
obj.interest_shares = delta;
eosio_assert( delta >= 0, "underflow" );
});
} else {
l.modify( existing, 0, [&]( auto& obj ) {
obj.interest_shares += delta;
eosio_assert( obj.interest_shares >= 0, "underflow" );
});
}
}
void market_state::cover_margin( account_name borrower, const extended_asset& cover_amount ) {
if( cover_amount.get_extended_symbol() == exstate.base.balance.get_extended_symbol() ) {
cover_margin( borrower, base_margins, exstate.base, cover_amount );
} else if( cover_amount.get_extended_symbol() == exstate.quote.balance.get_extended_symbol() ) {
cover_margin( borrower, quote_margins, exstate.quote, cover_amount );
} else {
eosio_assert( false, "invalid debt asset" );
}
}
/**
* This method will use the collateral to buy the borrowed asset from the market
* with collateral to cancel the debt.
*/
void market_state::cover_margin( account_name borrower, margins& m, exchange_state::connector& c,
const extended_asset& cover_amount )
{
auto existing = m.find( borrower );
eosio_assert( existing != m.end(), "no known margin position" );
eosio_assert( existing->borrowed.amount >= cover_amount.amount, "attempt to cover more than user has" );
auto tmp = exstate;
auto estcol = tmp.convert( cover_amount, existing->collateral.get_extended_symbol() );
auto debpaid = exstate.convert( estcol, cover_amount.get_extended_symbol() );
eosio_assert( debpaid.amount >= cover_amount.amount, "unable to cover debt" );
auto refundcover = debpaid - cover_amount;
auto refundcol = exstate.convert( refundcover, existing->collateral.get_extended_symbol() );
estcol.amount -= refundcol.amount;
if( existing->borrowed.amount == cover_amount.amount ) {
auto freedcollateral = existing->collateral - estcol;
m.erase( existing );
existing = m.begin();
_accounts.adjust_balance( borrower, freedcollateral );
}
else {
m.modify( existing, 0, [&]( auto& obj ) {
obj.collateral.amount -= estcol.amount;
obj.borrowed.amount -= cover_amount.amount;
obj.call_price = double(obj.borrowed.amount) / obj.collateral.amount;
});
}
c.peer_margin.total_lent.amount -= cover_amount.amount;
if( existing != m.end() ) {
if( existing->call_price < c.peer_margin.least_collateralized )
c.peer_margin.least_collateralized = existing->call_price;
} else {
c.peer_margin.least_collateralized = std::numeric_limits<double>::max();
}
}
void market_state::update_margin( account_name borrower, const extended_asset& delta_debt, const extended_asset& delta_col )
{
if( delta_debt.get_extended_symbol() == exstate.base.balance.get_extended_symbol() ) {
adjust_margin( borrower, base_margins, exstate.base, delta_debt, delta_col );
} else if( delta_debt.get_extended_symbol() == exstate.quote.balance.get_extended_symbol() ) {
adjust_margin( borrower, quote_margins, exstate.quote, delta_debt, delta_col );
} else {
eosio_assert( false, "invalid debt asset" );
}
}
void market_state::adjust_margin( account_name borrower, margins& m, exchange_state::connector& c,
const extended_asset& delta_debt, const extended_asset& delta_col )
{
auto existing = m.find( borrower );
if( existing == m.end() ) {
eosio_assert( delta_debt.amount > 0, "cannot borrow neg" );
eosio_assert( delta_col.amount > 0, "cannot have neg collat" );
existing = m.emplace( borrower, [&]( auto& obj ) {
obj.owner = borrower;
obj.borrowed = delta_debt;
obj.collateral = delta_col;
obj.call_price = double(obj.borrowed.amount) / obj.collateral.amount;
});
} else {
if( existing->borrowed.amount == -delta_debt.amount ) {
eosio_assert( existing->collateral.amount == -delta_col.amount, "user failed to claim all collateral" );
m.erase( existing );
existing = m.begin();
} else {
m.modify( existing, 0, [&]( auto& obj ) {
obj.borrowed += delta_debt;
obj.collateral += delta_col;
obj.call_price = double(obj.borrowed.amount) / obj.collateral.amount;
});
}
}
c.peer_margin.total_lent += delta_debt;
eosio_assert( c.peer_margin.total_lent.amount <= c.peer_margin.total_lendable.amount, "insufficient funds availalbe to borrow" );
if( existing != m.end() ) {
if( existing->call_price < c.peer_margin.least_collateralized )
c.peer_margin.least_collateralized = existing->call_price;
eosio_assert( !exstate.requires_margin_call( c ), "this update would trigger a margin call" );
} else {
c.peer_margin.least_collateralized = std::numeric_limits<double>::max();
}
}
void market_state::save() {
market_table.modify( market_state_itr, 0, [&]( auto& s ) {
s = exstate;
});
}
}
#pragma once
#include <exchange/exchange_state.hpp>
#include <exchange/exchange_accounts.hpp>
namespace eosio {
/**
* We calculate a unique scope for each market/borrowed_symbol/collateral_symbol and then
* instantiate a table of margin positions... with in this table each user has exactly
* one position and therefore the owner can serve as the primary key.
*/
struct margin_position {
account_name owner;
extended_asset borrowed;
extended_asset collateral;
double call_price = 0;
uint64_t get_call()const { return uint64_t(1000000*call_price); }
uint64_t primary_key()const { return owner; }
EOSLIB_SERIALIZE( margin_position, (owner)(borrowed)(collateral)(call_price) )
};
typedef eosio::multi_index<N(margins), margin_position,
indexed_by<N(callprice), eosio::const_mem_fun<margin_position, uint64_t, &margin_position::get_call> >
> margins;
struct loan_position {
account_name owner; /// the owner
double interest_shares; /// the number of shares in the total lent pool
uint64_t primary_key()const { return owner; }
EOSLIB_SERIALIZE( loan_position, (owner)(interest_shares) )
};
typedef eosio::multi_index<N(loans), loan_position> loans;
/**
* Maintains a state along with the cache of margin positions and/or limit orders.
*/
struct market_state {
market_state( account_name this_contract, symbol_type market_symbol, exchange_accounts& acnts );
const exchange_state& initial_state()const;
void margin_call( extended_symbol debt_type );
void lend( account_name lender, const extended_asset& debt );
void unlend( account_name lender, double ishares, const extended_symbol& sym );
void update_margin( account_name borrower, const extended_asset& delta_debt,
const extended_asset& delta_collateral );
void cover_margin( account_name borrower, const extended_asset& cover_amount );
void save();
symbol_name marketid;
exchange_state exstate;
markets market_table;
margins base_margins;
margins quote_margins;
loans base_loans;
loans quote_loans;
private:
exchange_accounts& _accounts;
markets::const_iterator market_state_itr;
void cover_margin( account_name borrower, margins& m, exchange_state::connector& c,
const extended_asset& cover_amount );
void adjust_margin( account_name borrower, margins& m, exchange_state::connector& c,
const extended_asset& delta_debt, const extended_asset& delta_col );
void adjust_lend_shares( account_name lender, loans& l, double delta );
void margin_call( exchange_state::connector& c, margins& m );
};
} /// namespace eosio
Pegged Derivitive Currency Design
-----------------------
A Derivitive uses a price feed and collateral to enable two or
more parties to speculate on the future price of anything and to
settle their speculation in terms of the collateral.
A currency is designed to be a fungible and non-callable asset.
A pegged derivitive currency, such as BitUSD, is backed by a cryptocurrency
held as collateral. The "issuer" is "short" the dollar and extra-long the cryptocurrency.
The buyer is simply long the dollar.
Background
----------
BitShares created the first working pegged asset system by allowing anyone to take out
a short position by posting collateral and issuing BitUSD at a minimum 1.5:1 collateral:debt
ratio. The least collateralized position was forced to provide liquidity for BitUSD holders
any time the market price fell more than a couple percent below the dollar (if the BitUSD holder opted to use forced liquidation).
To prevent abuse of the price feed, all forced liquidation was delayed.
In the event of a "black swan" all shorts have their positions liquidated at the price feed and all holders of BitUSD are only
promised a fixed redemption rate.
There are several problems with this design:
1. There is very poor liquidity in the BitUSD / BitShares market creating large spreads
2. The shorts take all the risk and only profit when the price of BitShares rises
3. Blackswans are perminentant and very disruptive.
4. It is "every short for themselves"
5. Due to the risk/reward ratio the supply can be limited
6. The collateral requirements limit opportunity for leverage.
New Approach
------------
We present a new approach to pegged assets where the short-positions cooperate to provide the
service of a pegged asset with high liquidity. They make money by encouraging people to trade
their pegged asset and earning income from the trading fees rather than seeking heavy leverage
in a speculative market. They also generate money by earning interest on personal short positions.
The Setup Process
-----------------
An initial user deposits a collateral currency (C) into an smart contract and provides the initial
price feed. A new Debt token (D) is issued based upon the price feed and a 5:1 C:D ratio and the
issued tokens are deposited into the Bancor market maker. At this point in time there is 0 leverage by
the market maker because no D have been sold. The initial user is also issued exchange tokens E in the
market maker.
At this point people can buy E or D and the Bancor algorithm will provide liquidity between C, E, and D. Due to
the fees charged by the the market maker the value of E will increase in terms of C.
Maintaining the Peg
-------------------
To maximize the utility of the D token, the market maker needs to maintain a narrow trading range of D vs the Dollar. The
more consistant and reliable this trading range is, the more people will be willing to hold and trade D. There are several
situations that can occur:
1. D is trading above a dollar +5%
a. Maker is fully collateralized at 5:1
- issue new D and deposit into maker such that collateral ratio is 5:1
b. Maker is not fully collateralized
- adjust the maker weights to lower the redemption prices (defending capital of maker), arb will probably prevent this reality.
2. D is selling for less than a dollar -5%
a. Maker is fully collateralized at more than 1.5:1
- adjust the maker weights to increase redemption prices
c. Maker is under collateralized less than 1.5:1
- stop E -> C and E -> D trades.
- offer bonus on C->E and D->E trades.
- on D->E conversions take received D out of circulation rather than add to maker
- on C<->D conversion continue as normal
- stop attempting adjusting maker ratio to defend the price feed and let the price float unless price is above +1%
Value of E = C - D where D == all in circulation, so E->C conversions should always assume all outstanding
D was settled at current maker price. The result of such a conversion will lower the collateral ratio, unless they are forced
to buy and retire some D at the current ratio. The algorithm must ensure the individual selling E doesn't leave those holding E
worse-off from a D/E perspective. An individual buying E will create new D to maintain the same D/E ratio.
This implies that when value of all outstanding D is greater than all C that E cannot be sold until the network
generates enough in trading fees to recaptialize the market. This is like a company with more debt than equity not allowing buybacks. In fact, E should
not be sellable any time the collateral ratio falls below 1.5:1. In exchanges like BitShares this is typical margin call
territory, but in this system holders of E have a chance at future liquidity if the situation improves. While E is not sellable
E can be purchased at a 10% discount to its theoretical value, this will dilute existing holders of E but will raise capital and
hopefully move E holders closer to eventual liquidity.
Adjusting Bancor Ratios by Price Feed
-------------------------------------
The price feed informs the algorithm of significant deviations between the Bancor price and the target peg. The price feed
is necisarially a lagging indicator and may also factor in natural spreads between different exchanges. Therefore, the price
feed shall have no impact unless there is a significant deviation (5%). When such a deviation occurs, the ratio is adjusted such
that there is still a 4% difference. In other words, the price feed keeps the maker in the "channel" but does not attempt to
set the real-time prices. If there is a sudden change and the pricefeed differs from maker by 50% then after the adjustment it will
still differ by 4%.
Summary
-------
Under this model holders of E are short the dollar and make money to recollateralize their positions via market activity. Anyone
selling E must realize the losses as a result of being short. Anyone buying E can get in to take their place at the current collateral ratio.
The value of E is equal to the value of a margin postion.
Anyone can buy E for a combination C and D equal to the current collateral ratio.
Anyone may sell E for a personal margin position with equal ratio of C and D
Anyone may buy E with a personal margin position
If they only have C, then they must use some of C to buy D first (which will move the price)
If they only have D, then they must use some of D to buy C first (which will also move the price)
Anyone can buy and sell E based upon Bancor balances of C and (all D), they must sell their E for a combination of D and C at current ratio, then sell the C or D for the other.
Anytime collateral level falls below 1.5 selling E is blocked and buying of E is given a 10% bonus.
Anyone can convert D<->C using Bancor maker configured to maintain price within +/- 5% of the price feed.
此差异已折叠。
......@@ -155,7 +155,7 @@ namespace identity {
uint64_t primary_key() const { return account; }
EOSLIB_SERIALIZE( trustrow, (account) );
EOSLIB_SERIALIZE( trustrow, (account) )
};
typedef eosio::multi_index<N(certs), certrow,
......@@ -191,7 +191,7 @@ namespace identity {
}
} else if (DeployToAccount == current_receiver()){
//the certifier is no longer trusted, need to unset the flag
certs.update(*itr, 0, [&](certrow& r) {
idx.modify(itr, 0, [&](certrow& r) {
r.trusted = 0;
});
} else {
......@@ -216,7 +216,7 @@ namespace identity {
if (ident == get_claimed_identity(account) && is_trusted(itr->certifier)) {
if (DeployToAccount == current_receiver()) {
// the certifier became trusted and we have permissions to update the flag
certs.update(*itr, 0, [&](certrow& r) {
idx.modify(itr, 0, [&](certrow& r) {
r.trusted = 1;
});
}
......@@ -244,7 +244,7 @@ namespace identity {
static bool is_trusted_by( account_name trusted, account_name by ) {
trust_table t( code, by );
return t.find( trusted );
return t.find( trusted ) != t.end();
}
static bool is_trusted( account_name acnt ) {
......@@ -266,21 +266,21 @@ namespace identity {
require_recipient( t.trusting );
trust_table table( code, t.trustor );
auto ptr = table.find(t.trusting);
if (!ptr && t.trust > 0) {
auto itr = table.find(t.trusting);
if( itr == table.end() && t.trust > 0 ) {
table.emplace( t.trustor, [&](trustrow& row) {
row.account = t.trusting;
});
} else if (ptr && t.trust == 0) {
table.remove(*ptr);
} else if( itr != table.end() && t.trust == 0 ) {
table.erase(itr);
}
}
static void on( const create& c ) {
require_auth( c.creator );
idents_table t( code, code);
auto ptr = t.find( c.identity );
eosio_assert( !ptr, "identity already exists" );
auto itr = t.find( c.identity );
eosio_assert( itr == t.end(), "identity already exists" );
eosio_assert( c.identity != 0, "identity=0 is not allowed" );
t.emplace(c.creator, [&](identrow& i) {
i.identity = c.identity;
......@@ -294,8 +294,7 @@ namespace identity {
require_auth( cert.bill_storage_to );
idents_table t( code, code );
auto ptr = t.find( cert.identity );
eosio_assert( ptr != nullptr, "identity does not exist" );
eosio_assert( t.find( cert.identity ) != t.end(), "identity does not exist" );
/// the table exists in the scope of the identity
certs_table certs( code, cert.identity );
......@@ -308,7 +307,7 @@ namespace identity {
auto itr = idx.lower_bound( certrow::key(value.property, trusted, cert.certifier) );
if (itr != idx.end() && itr->property == value.property && itr->trusted == trusted && itr->certifier == cert.certifier) {
certs.update(*itr, 0, [&](certrow& row) {
idx.modify(itr, 0, [&](certrow& row) {
row.confidence = value.confidence;
row.type = value.type;
row.data = value.data;
......@@ -328,7 +327,7 @@ namespace identity {
auto itr_old = idx.lower_bound( certrow::key(value.property, !trusted, cert.certifier) );
if (itr_old != idx.end() && itr_old->property == value.property && itr_old->trusted == !trusted && itr_old->certifier == cert.certifier) {
certs.remove(*itr_old);
idx.erase(itr_old);
}
//special handling for owner
......@@ -343,13 +342,13 @@ namespace identity {
bool removed = false;
auto itr = idx.lower_bound( certrow::key(value.property, trusted, cert.certifier) );
if (itr != idx.end() && itr->property == value.property && itr->trusted == trusted && itr->certifier == cert.certifier) {
certs.remove(*itr);
idx.erase(itr);
} else {
removed = true;
}
itr = idx.lower_bound( certrow::key(value.property, !trusted, cert.certifier) );
if (itr != idx.end() && itr->property == value.property && itr->trusted == !trusted && itr->certifier == cert.certifier) {
certs.remove(*itr);
idx.erase(itr);
} else {
removed = true;
}
......
......@@ -25,14 +25,14 @@ namespace identity_test {
{
uint64_t identity;
EOSLIB_SERIALIZE( get_owner_for_identity, (identity) );
EOSLIB_SERIALIZE( get_owner_for_identity, (identity) )
};
struct get_identity_for_account : public action_meta< code, N(getidentity) >
{
account_name account ;
EOSLIB_SERIALIZE( get_identity_for_account, (account) );
EOSLIB_SERIALIZE( get_identity_for_account, (account) )
};
typedef singleton<code, N(result), code, uint64_t> result_table;
......
Subproject commit 959b01fb8b617851e260bd2218ac8ba74269fec9
Subproject commit 2880ac42909d4bb29687ed079f8bb4405c3b0869
file(GLOB ABI_FILES "*.abi")
set(ABI_FILES "multi_index_test.abi")
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_wast_executable(TARGET multi_index_test
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}"
LIBRARIES libc++ libc eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
......@@ -56,13 +56,13 @@ struct limit_order {
indexed_by< N(byprice), const_mem_fun<limit_order, uint128_t, &limit_order::get_price> >
> orders( N(multitest), N(multitest) );
const auto& order1 = orders.emplace( payer, [&]( auto& o ) {
orders.emplace( payer, [&]( auto& o ) {
o.id = 1;
o.expiration = 300;
o.owner = N(dan);
});
const auto& order2 = orders.emplace( payer, [&]( auto& o ) {
auto order2 = orders.emplace( payer, [&]( auto& o ) {
o.id = 2;
o.expiration = 200;
o.owner = N(alice);
......@@ -80,8 +80,8 @@ struct limit_order {
print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name(item.owner), "\n");
}
print("Updating expiration of order with ID=2 to 400.\n");
orders.update( order2, payer, [&]( auto& o ) {
print("Modifying expiration of order with ID=2 to 400.\n");
orders.modify( order2, payer, [&]( auto& o ) {
o.expiration = 400;
});
......@@ -103,22 +103,22 @@ struct limit_order {
indexed_by< N(byval), const_mem_fun<test_k256, key256, &test_k256::get_val> >
> testtable( N(multitest), N(exchange) ); // Code must be same as the receiver? Scope doesn't have to be.
const auto& entry1 = testtable.emplace( payer, [&]( auto& o ) {
testtable.emplace( payer, [&]( auto& o ) {
o.id = 1;
o.val = key256::make_from_word_sequence<uint64_t>(0ULL, 0ULL, 0ULL, 42ULL);
});
const auto& entry2 = testtable.emplace( payer, [&]( auto& o ) {
testtable.emplace( payer, [&]( auto& o ) {
o.id = 2;
o.val = key256::make_from_word_sequence<uint64_t>(1ULL, 2ULL, 3ULL, 4ULL);
});
const auto& entry3 = testtable.emplace( payer, [&]( auto& o ) {
testtable.emplace( payer, [&]( auto& o ) {
o.id = 3;
o.val = key256::make_from_word_sequence<uint64_t>(0ULL, 0ULL, 0ULL, 42ULL);
});
const auto* e = testtable.find( 2 );
auto itr = testtable.find( 2 );
print("Items sorted by primary key:\n");
for( const auto& item : testtable ) {
......@@ -133,7 +133,7 @@ struct limit_order {
auto lower2 = validx.lower_bound(key256::make_from_word_sequence<uint64_t>(0ULL, 0ULL, 0ULL, 50ULL));
print("First entry with a val of at least 50 has ID=", lower2->id, ".\n");
if( &*lower2 == e ) {
if( testtable.iterator_to(*lower2) == itr ) {
print("Previously found entry is the same as the one found earlier with a primary key value of 2.\n");
}
......@@ -148,7 +148,7 @@ struct limit_order {
print("First entry with a val greater than 42 has ID=", upper->id, ".\n");
print("Removed entry with ID=", lower1->id, ".\n");
testtable.remove( *lower1 );
validx.erase( lower1 );
print("Items sorted by primary key:\n");
for( const auto& item : testtable ) {
......
......@@ -4,7 +4,7 @@ file(GLOB ENV_SOURCES "upstream/src/env/*.c")
file(GLOB ERRNO_SOURCES "upstream/src/errno/*.c")
file(GLOB EXIT_SOURCES "upstream/src/exit/*.c")
file(GLOB LOCALE_SOURCES "upstream/src/locale/*.c")
file(GLOB MALLOC_SOURCES "upstream/src/malloc/*.c")
file(GLOB MATH_SOURCES "upstream/src/math/*.c")
file(GLOB MBYTE_SOURCES "upstream/src/multibyte/*.c")
file(GLOB MISC_SOURCES "upstream/src/misc/*.c")
file(GLOB SEARCH_SOURCES "upstream/src/search/*.c")
......@@ -13,12 +13,12 @@ file(GLOB STDLIB_SOURCES "upstream/src/stdlib/*.c")
file(GLOB STRING_SOURCES "upstream/src/string/*.c")
file(GLOB TIME_SOURCES "upstream/src/time/*.c")
file(GLOB THREAD_SOURCES "upstream/src/thread/*.c") #only for __lock __unlock
set(INTERNAL_SOURCES upstream/src/internal/intscan.c upstream/src/internal/shgetc.c upstream/src/internal/libc.c)
set(INTERNAL_SOURCES upstream/src/internal/floatscan.c upstream/src/internal/intscan.c upstream/src/internal/shgetc.c upstream/src/internal/libc.c)
add_wast_library(TARGET libc
NOWARNINGS
SOURCE_FILES ${CRYPT_SOURCES} ${CTYPE_SOURCES} ${ENV_SOURCES} ${ERRNO_SOURCES} ${EXIT_SOURCES} ${INTERNAL_SOURCES} ${LOCALE_SOURCES} ${MBYTE_SOURCES}
${MISC_SOURCES} ${SEARCH_SOURCES} ${STDIO_SOURCES} ${STDLIB_SOURCES} ${STRING_SOURCES} ${TIME_SOURCES} ${THREAD_SOURCES}
SOURCE_FILES ${CRYPT_SOURCES} ${CTYPE_SOURCES} ${ENV_SOURCES} ${ERRNO_SOURCES} ${EXIT_SOURCES} ${INTERNAL_SOURCES} ${LOCALE_SOURCES} ${MATH_SOURCES}
${MBYTE_SOURCES} ${MISC_SOURCES} ${SEARCH_SOURCES} ${STDIO_SOURCES} ${STDLIB_SOURCES} ${STRING_SOURCES} ${TIME_SOURCES} ${THREAD_SOURCES}
INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include
${CMAKE_SOURCE_DIR}/contracts/musl/upstream/src/internal
${CMAKE_SOURCE_DIR}/contracts/musl/upstream/arch/eos
......
Subproject commit ee49ba896db1de3c3e4f4285eb4e285b641a6cd9
Subproject commit 8a34536ac9764c90c86cc0b62d0cda07449fd5d8
......@@ -7,8 +7,6 @@
#include <eosiolib/eosio.hpp>
#include <eosiolib/dispatcher.hpp>
using namespace eosio;
namespace noop {
using std::string;
......
......@@ -5,7 +5,7 @@
#include <proxy/proxy.hpp>
#include <eosio.system/eosio.system.hpp>
#include <eosiolib/transaction.hpp>
#include <currency/currency.hpp>
#include <eosiolib/currency.hpp>
namespace proxy {
using namespace eosio;
......@@ -51,7 +51,7 @@ namespace proxy {
configs::store(code_config, self);
transaction out;
out.actions.emplace_back(vector<permission_level>{{self, N(active)}}, new_transfer);
out.actions.emplace_back(permission_level{self, N(active)}, N(currency), N(transfer), new_transfer);
out.send(id, now() + code_config.delay);
}
}
......@@ -96,7 +96,7 @@ extern "C" {
}
} else if ( code == N(currency) ) {
if( action == N(transfer) ) {
apply_transfer(code, unpack_action<currency::contract::transfer_memo>());
apply_transfer(code, unpack_action<eosio::currency::transfer>());
}
} else if (code == current_receiver() ) {
if ( action == N(setowner)) {
......
......@@ -35,7 +35,7 @@ namespace simpledb {
int16_t i16;
int8_t i8;
EOSLIB_SERIALIZE( record1, (key)(u128)(u64)(u32)(u16)(u8)(i64)(i32)(i16)(i8) );
EOSLIB_SERIALIZE( record1, (key)(u128)(u64)(u32)(u16)(u8)(i64)(i32)(i16)(i8) )
};
//@abi action insert1
......@@ -46,7 +46,7 @@ namespace simpledb {
store_i64( N(simpledb), N(record1), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record1, (r1) );
EOSLIB_SERIALIZE( insert_record1, (r1) )
};
//@abi action remove1
......@@ -56,7 +56,7 @@ namespace simpledb {
remove_i64( N(simpledb), N(record1), (char *)this);
}
EOSLIB_SERIALIZE( remove_record1, (key) );
EOSLIB_SERIALIZE( remove_record1, (key) )
};
//@abi table
......@@ -64,7 +64,7 @@ namespace simpledb {
uint128_t key1;
uint128_t key2;
EOSLIB_SERIALIZE( record2, (key1)(key2) );
EOSLIB_SERIALIZE( record2, (key1)(key2) )
};
//@abi action insert2
......@@ -75,7 +75,7 @@ namespace simpledb {
store_i128i128( N(simpledb), N(record2), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record2, (r2) );
EOSLIB_SERIALIZE( insert_record2, (r2) )
};
//@abi action remove2
......@@ -86,7 +86,7 @@ namespace simpledb {
remove_i128i128( N(simpledb), N(record2), b.data());
}
EOSLIB_SERIALIZE( remove_record2, (key) );
EOSLIB_SERIALIZE( remove_record2, (key) )
};
//@abi table
......@@ -95,7 +95,7 @@ namespace simpledb {
uint64_t key2;
uint64_t key3;
EOSLIB_SERIALIZE( record3, (key1)(key2)(key3) );
EOSLIB_SERIALIZE( record3, (key1)(key2)(key3) )
};
//@abi action insert3
......@@ -106,7 +106,7 @@ namespace simpledb {
store_i128i128( N(simpledb), N(record3), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record3, (r3) );
EOSLIB_SERIALIZE( insert_record3, (r3) )
};
//@abi action remove3
......@@ -117,7 +117,7 @@ namespace simpledb {
remove_i64i64i64( N(simpledb), N(record2), b.data());
}
EOSLIB_SERIALIZE( remove_record3, (key) );
EOSLIB_SERIALIZE( remove_record3, (key) )
};
//@abi table
......@@ -125,7 +125,7 @@ namespace simpledb {
std::string key;
std::string value;
EOSLIB_SERIALIZE( key_value1, (key)(value) );
EOSLIB_SERIALIZE( key_value1, (key)(value) )
};
//@abi action insertkv1
......@@ -137,7 +137,7 @@ namespace simpledb {
// store_str( N(simpledb), N(keyvalue1), N(simpledb), (char *)kv1.key.data(), kv1.key.size(), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_keyvalue1, (kv1) );
EOSLIB_SERIALIZE( insert_keyvalue1, (kv1) )
};
//@abi action removekv1
......@@ -148,14 +148,14 @@ namespace simpledb {
//remove_str( N(simpledb), N(keyvalue1), (char *)key.data(), key.size() );
}
EOSLIB_SERIALIZE( remove_keyvalue1, (key) );
EOSLIB_SERIALIZE( remove_keyvalue1, (key) )
};
struct complex_type {
std::string name;
uint64_t age;
EOSLIB_SERIALIZE( complex_type, (name)(age) );
EOSLIB_SERIALIZE( complex_type, (name)(age) )
};
//@abi table
......@@ -163,7 +163,7 @@ namespace simpledb {
std::string key;
complex_type value;
EOSLIB_SERIALIZE( key_value2, (key)(value) );
EOSLIB_SERIALIZE( key_value2, (key)(value) )
};
//@abi action insertkv2
......@@ -175,7 +175,7 @@ namespace simpledb {
// store_str( N(simpledb), N(keyvalue2), N(simpledb), (char *)kv2.key.data(), kv2.key.size(), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_keyvalue2, (kv2) );
EOSLIB_SERIALIZE( insert_keyvalue2, (kv2) )
};
//@abi action removekv2
......@@ -185,7 +185,7 @@ namespace simpledb {
remove_str( N(simpledb), N(keyvalue2), (char *)key.data(), key.size() );
}
EOSLIB_SERIALIZE( remove_keyvalue2, (key) );
EOSLIB_SERIALIZE( remove_keyvalue2, (key) )
};
template<typename ...Ts>
......
......@@ -13,7 +13,7 @@
"name": "set_global_limits",
"base": "",
"fields": [
{"name":"cpu_usec_per_period", "type":"int64"},
{"name":"cpu_usec_per_period", "type":"int64"}
]
},{
"name": "producer_key",
......@@ -33,7 +33,7 @@
"name": "require_auth",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"from", "type":"account_name"}
]
},{
"name": "nonce",
......@@ -60,4 +60,4 @@
}
],
"tables": []
}
\ No newline at end of file
}
......@@ -38,11 +38,11 @@ void test_action::read_action_normal() {
}
void test_action::read_action_to_0() {
uint32_t total = read_action((void *)0, action_size());
read_action((void *)0, action_size());
}
void test_action::read_action_to_64k() {
uint32_t total = read_action( (void *)((1<<16)-2), action_size());
read_action( (void *)((1<<16)-2), action_size());
}
void test_action::require_notice() {
......
......@@ -23,8 +23,7 @@ extern "C" {
}
void apply( unsigned long long code, unsigned long long action ) {
void apply( unsigned long long, unsigned long long action ) {
//eosio::print("==> CONTRACT: ", code, " ", action, "\n");
//test_types
WASM_TEST_HANDLER(test_types, types_size);
......@@ -65,6 +64,7 @@ extern "C" {
WASM_TEST_HANDLER(test_print, test_prints);
WASM_TEST_HANDLER(test_print, test_prints_l);
WASM_TEST_HANDLER(test_print, test_printi);
WASM_TEST_HANDLER(test_print, test_printui);
WASM_TEST_HANDLER(test_print, test_printi128);
WASM_TEST_HANDLER(test_print, test_printn);
......
......@@ -51,6 +51,7 @@ struct test_print {
static void test_prints();
static void test_prints_l();
static void test_printi();
static void test_printui();
static void test_printi128();
static void test_printn();
};
......@@ -69,7 +70,7 @@ struct test_action {
static void assert_false();
static void assert_true();
static void now();
static void test_abort();
static void test_abort() __attribute__ ((noreturn)) ;
static void test_current_receiver();
static void test_current_sender();
static void test_publication_time();
......@@ -141,6 +142,7 @@ struct test_multi_index {
static void idx128_autoincrement_test_part1();
static void idx128_autoincrement_test_part2();
static void idx256_general();
static void idx_double_general();
};
struct test_crypto {
......
......@@ -193,24 +193,23 @@ struct sig_hash_key {
void test_crypto::test_recover_key_assert_true() {
sig_hash_key sh;
int read = read_action( (char*)&sh, sizeof(sh) );
public_key public_key;
read_action( (char*)&sh, sizeof(sh) );
assert_recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), (const char*)&sh.pk, sizeof(sh.pk) );
}
void test_crypto::test_recover_key_assert_false() {
sig_hash_key sh;
int read = read_action( (char*)&sh, sizeof(sh) );
read_action( (char*)&sh, sizeof(sh) );
assert_recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), (const char*)&sh.pk, sizeof(sh.pk) );
eosio_assert( false, "should have thrown an error" );
}
void test_crypto::test_recover_key() {
sig_hash_key sh;
int read = read_action( (char*)&sh, sizeof(sh) );
read_action( (char*)&sh, sizeof(sh) );
public_key pk;
int recovered = recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), pk.data, sizeof(pk) );
for ( int i=0; i < sizeof(pk); i++ )
recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), pk.data, sizeof(pk) );
for ( uint32_t i=0; i < sizeof(pk); i++ )
if ( pk.data[i] != sh.pk.data[i] )
eosio_assert( false, "public key does not match" );
}
......@@ -284,8 +283,6 @@ void test_crypto::test_ripemd160() {
void test_crypto::sha256_null() {
checksum256 tmp;
int a = 3;
int* b = &a;
sha256(nullptr, 100, &tmp);
//eosio_assert(false, "should've thrown an error");
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -14,7 +14,7 @@ extern "C" {
}
void apply( unsigned long long code, unsigned long long action ) {
void apply( unsigned long long, unsigned long long action ) {
//eosio::print("==> CONTRACT: ", code, " ", action, "\n");
......
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst" PARENT_SCOPE)
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册