├── bank.cdp ├── bank.cdp.clauses.md ├── perm.json ├── bank.cdp.contracts.md ├── README.md └── bank.cdp.hpp ├── bank.price ├── bank.price.clauses.md ├── .gitignore ├── bank.price.contracts.md ├── bank.price.hpp └── bank.price.cpp ├── bank.shares ├── bank.shares.clauses.md ├── .gitignore ├── bank.shares.contracts.md ├── bank.shares.hpp └── bank.shares.cpp ├── tests ├── .npmrc ├── .gitignore ├── test_contracts │ └── eosio.token │ │ ├── eosio.token.wasm │ │ └── eosio.token.abi ├── package.json ├── contracts.hpp.in ├── main.cpp ├── CMakeLists.txt ├── token_test_api.hpp ├── pay2key.sign.js ├── fraxloans_api.hpp ├── pay2key.test.sh ├── fraxloans_tests.cpp ├── fraxreserve.test.sh └── bootstrapper.sh ├── .gitignore ├── bank.safesnd ├── .gitignore └── bank.safesnd.cpp ├── .vscode └── ipch │ ├── 9be19420ea84d26 │ └── mmap_address.bin │ ├── 962ae4baae37eef2 │ └── mmap_address.bin │ ├── 40b43f10a57533ca │ └── mmap_address.bin │ ├── 473a364231b97ad3 │ └── mmap_address.bin │ ├── 95e3618d48d72b60 │ └── mmap_address.bin │ └── c7e0da3d6d198114 │ └── mmap_address.bin ├── bank.pay2key ├── relay-server │ ├── .gitignore │ ├── SAMPLE.env │ ├── package.json │ ├── README.md │ ├── relayer.js │ └── package-lock.json ├── .gitignore ├── frontend │ ├── public │ │ ├── favicon.ico │ │ ├── manifest.json │ │ └── index.html │ ├── src │ │ ├── index.js │ │ ├── App.css │ │ ├── index.css │ │ └── App.js │ ├── .gitignore │ ├── package.json │ └── README.md ├── js_test │ ├── package.json │ ├── test.js │ └── package-lock.json ├── LICENSE ├── bank.pay2key.hpp ├── bank.pay2key.abi ├── README.md ├── base58.c └── bank.pay2key.cpp ├── .DS_Store ├── frax.reserve ├── a.out ├── CMakeLists.txt ├── frax.reserve.hpp ├── frax.reserve.abi └── frax.reserve.cpp ├── frax.loans ├── CMakeLists.txt ├── frax.loans.hpp └── frax.loans.cpp ├── UnitTestsExternalProject.txt ├── README.md └── CMakeLists.txt /bank.cdp/bank.cdp.clauses.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bank.price/bank.price.clauses.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bank.shares/bank.shares.clauses.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.swp 3 | build/ 4 | -------------------------------------------------------------------------------- /bank.price/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.abi 3 | -------------------------------------------------------------------------------- /bank.shares/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.abi 3 | -------------------------------------------------------------------------------- /bank.safesnd/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.abi 3 | -------------------------------------------------------------------------------- /.vscode/ipch/9be19420ea84d26/mmap_address.bin: -------------------------------------------------------------------------------- 1 | 8A -------------------------------------------------------------------------------- /.vscode/ipch/962ae4baae37eef2/mmap_address.bin: -------------------------------------------------------------------------------- 1 | L4 -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | -------------------------------------------------------------------------------- /bank.pay2key/relay-server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentralbanknetwork/bank.contracts/HEAD/.DS_Store -------------------------------------------------------------------------------- /bank.pay2key/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.wast 3 | .vscode 4 | .DS_Store 5 | js_test/node_modules/** 6 | -------------------------------------------------------------------------------- /frax.reserve/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentralbanknetwork/bank.contracts/HEAD/frax.reserve/a.out -------------------------------------------------------------------------------- /bank.pay2key/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentralbanknetwork/bank.contracts/HEAD/bank.pay2key/frontend/public/favicon.ico -------------------------------------------------------------------------------- /.vscode/ipch/40b43f10a57533ca/mmap_address.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentralbanknetwork/bank.contracts/HEAD/.vscode/ipch/40b43f10a57533ca/mmap_address.bin -------------------------------------------------------------------------------- /.vscode/ipch/473a364231b97ad3/mmap_address.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentralbanknetwork/bank.contracts/HEAD/.vscode/ipch/473a364231b97ad3/mmap_address.bin -------------------------------------------------------------------------------- /.vscode/ipch/95e3618d48d72b60/mmap_address.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentralbanknetwork/bank.contracts/HEAD/.vscode/ipch/95e3618d48d72b60/mmap_address.bin -------------------------------------------------------------------------------- /.vscode/ipch/c7e0da3d6d198114/mmap_address.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentralbanknetwork/bank.contracts/HEAD/.vscode/ipch/c7e0da3d6d198114/mmap_address.bin -------------------------------------------------------------------------------- /tests/test_contracts/eosio.token/eosio.token.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentralbanknetwork/bank.contracts/HEAD/tests/test_contracts/eosio.token/eosio.token.wasm -------------------------------------------------------------------------------- /bank.price/bank.price.contracts.md: -------------------------------------------------------------------------------- 1 |

create

2 | Create a new symbol to track. 3 |

update

4 | Update the price for a symbol. 5 | -------------------------------------------------------------------------------- /bank.pay2key/frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render(, document.getElementById('root')); 7 | -------------------------------------------------------------------------------- /frax.loans/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_contract(frax.loans frax.loans ${CMAKE_CURRENT_SOURCE_DIR}/frax.loans.cpp) 2 | target_include_directories(frax.loans.wasm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 3 | target_compile_options(frax.loans.wasm PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /frax.reserve/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_contract(frax.reserve frax.reserve ${CMAKE_CURRENT_SOURCE_DIR}/frax.reserve.cpp) 2 | target_include_directories(frax.reserve.wasm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 3 | target_compile_options(frax.reserve.wasm PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /bank.pay2key/relay-server/SAMPLE.env: -------------------------------------------------------------------------------- 1 | EOS_API_BASE=http://127.0.0.1:8888 2 | RELAYER_PRIVATE_KEY=************************************** 3 | RELAYER_PUBLIC_KEY=EOS6HfoynFKZ1Msq1bKNwtSTTpEu8NssYMcgsy6nHqhRp3mz7tNkB 4 | RELAYER_ACCOUNT=myeosaccount 5 | BTC_UTXO_ACCOUNT=paytobtckey1 6 | EOS_UTXO_ACCOUNT=paytoeoskey1 7 | -------------------------------------------------------------------------------- /bank.shares/bank.shares.contracts.md: -------------------------------------------------------------------------------- 1 |

startauction

2 | Start a reverse Dutch auction for the BANK/SYS token, in exchange for a given currency. 3 |

buyshares

4 | Buy the BANK/SYS token from a given auction using currency. 5 |

updateask

6 | Update the ask price for a given auction. 7 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "pay2key.sign.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bs58": "^4.0.1", 14 | "eosjs-ecc": "^4.0.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /bank.cdp/perm.json: -------------------------------------------------------------------------------- 1 | { 2 | "threshold": 1, 3 | "keys": [ 4 | { 5 | "key": "EOS6TnW2MQbZwXHWDHAYQazmdc3Sc1KGv4M9TSgsKZJSo43Uxs2Bx", 6 | "weight": 1 7 | } 8 | ], 9 | "accounts": [ 10 | { 11 | "permission": { 12 | "actor": "bank.cdp", 13 | "permission": "eosio.code" 14 | }, 15 | "weight": 1 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /bank.pay2key/frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "EOSIO UTXO Frontend", 3 | "name": "EOSIO UTXO Frontend", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /bank.pay2key/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /bank.pay2key/frontend/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | background-color: #282c34; 4 | min-height: 100vh; 5 | display: flex; 6 | flex-direction: column; 7 | align-items: center; 8 | justify-content: center; 9 | font-size: calc(10px + 2vmin); 10 | color: white; 11 | } 12 | 13 | .label { 14 | display: block; 15 | text-align: right; 16 | width: 430px; 17 | } 18 | 19 | .input { 20 | margin-left: 15px; 21 | } 22 | -------------------------------------------------------------------------------- /bank.pay2key/js_test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js_test", 3 | "version": "1.0.0", 4 | "description": "Test suite", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bs58": "^4.0.1", 13 | "eosjs-ecc": "^4.0.4" 14 | }, 15 | "devDependencies": { 16 | "shelljs": "^0.8.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bank.pay2key/frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /bank.pay2key/relay-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "relay-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node relayer.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@hapi/joi": "^15.0.0", 15 | "body-parser": "^1.19.0", 16 | "dotenv": "^7.0.0", 17 | "eosjs": "^20.0.0", 18 | "express": "^4.16.4", 19 | "morgan": "^1.9.1", 20 | "node-fetch": "^2.4.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bank.pay2key/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eosio_utxo_frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "bs58": "^4.0.1", 7 | "eosjs-ecc": "^4.0.4", 8 | "react": "^16.7.0", 9 | "react-dom": "^16.7.0", 10 | "react-scripts": "2.1.3" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test", 16 | "eject": "react-scripts eject" 17 | }, 18 | "eslintConfig": { 19 | "extends": "react-app" 20 | }, 21 | "browserslist": [ 22 | ">0.2%", 23 | "not dead", 24 | "not ie <= 11", 25 | "not op_mini all" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /UnitTestsExternalProject.txt: -------------------------------------------------------------------------------- 1 | include(ExternalProject) 2 | find_package(Git REQUIRED) 3 | include(GNUInstallDirs) 4 | 5 | string(REPLACE ";" "|" TEST_FRAMEWORK_PATH "${CMAKE_FRAMEWORK_PATH}") 6 | string(REPLACE ";" "|" TEST_MODULE_PATH "${CMAKE_MODULE_PATH}") 7 | 8 | ExternalProject_Add( 9 | contracts_unit_tests 10 | LIST_SEPARATOR | # Use the alternate list separator 11 | CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -DEOSIO_ROOT=${EOSIO_ROOT} -DLLVM_DIR=${LLVM_DIR} 12 | SOURCE_DIR ${CMAKE_SOURCE_DIR}/tests 13 | BINARY_DIR ${CMAKE_BINARY_DIR}/tests 14 | BUILD_ALWAYS 1 15 | TEST_COMMAND "" 16 | INSTALL_COMMAND "" 17 | ) 18 | -------------------------------------------------------------------------------- /bank.pay2key/relay-server/README.md: -------------------------------------------------------------------------------- 1 | # UTXO Relay Server 2 | 3 | This HTTP server exposes a single endpoint: 4 | 5 | `POST /relay`: Relay a UTXO tranasction with the parameters specified in the `.env` file. Seem `SAMPLE.env` for how to configure the environment. 6 | 7 | Example: 8 | 9 | ``` 10 | POST /relay 11 | Content-Type: application/json 12 | 13 | { 14 | "from": "EOS7PoGq46ssqeGh8ZNScWQxqbwg5RNvLAwVw3i5dQcZ3a1h9nRyr", 15 | "to": "EOS7VZbHpaEog944Wdw6XuddGBCYVGcy7W8QA5khtQP3dAgBVgB7T", 16 | "amount": "9.000 IQUTXO", 17 | "fee": "1.000 IQUTXO", 18 | "nonce": 6, 19 | "memo": "testing", 20 | "sig": "SIG_K1_K17GrShyMD6A84D9YkZn2CNioY6rDrKGTz7uCduHZ663cNfLq7ecvZqY9vJsPMExetVMwKTQeNMceKtopMj4iSo8nyXLEW" 21 | } 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Decentral Bank: Turing-Complete Currency and Banking Blockchain Network 2 | 3 | Decentral Bank is a new project headed by Everipedia execs Sam Kazemian and Kedar Iyer which seeks to build a new general-compute blockchain specially customized for central bank digital currencies, stablecoins, DeFi applications, stablecoins issuance, and DLT monetary policy. Join the public telegram group here: https://t.me/decentralbank 4 | 5 | The blockchain's base smart contract system is based on the EOSIO protocol with many customizations, consensus method changes, and new libraries for issuing stablecoins, building defi apps, and true privacy transactions. 6 | 7 | This repository houses the contracts for banking and monetary policy usage of the chain. Current modules in progress are: bond tokens and instruments, UTXO and MimbleWimble tokens, a debt/collateralization framework (CDP), and the network's native staking/consensus token. 8 | 9 | More information coming soon 10 | -------------------------------------------------------------------------------- /tests/contracts.hpp.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace eosio { namespace testing { 5 | 6 | struct contracts { 7 | static std::vector fraxloans_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../frax.loans/frax.loans.wasm"); } 8 | static std::vector fraxloans_abi() { return read_abi("${CMAKE_BINARY_DIR}/../frax.loans/frax.loans.abi"); } 9 | 10 | static std::vector fraxreserve_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../frax.reserve/frax.reserve.wasm"); } 11 | static std::vector fraxreserve_abi() { return read_abi("${CMAKE_BINARY_DIR}/../frax.reserve/frax.reserve.abi"); } 12 | 13 | static std::vector token_wasm() { return read_wasm("${CMAKE_SOURCE_DIR}/test_contracts/eosio.token/eosio.token.wasm"); } 14 | static std::vector token_abi() { return read_abi("${CMAKE_SOURCE_DIR}/test_contracts/eosio.token/eosio.token.abi"); } 15 | }; 16 | }} //ns eosio::testing 17 | -------------------------------------------------------------------------------- /bank.safesnd/bank.safesnd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace eosio; 5 | 6 | struct transfer_args { 7 | name from; 8 | name to; 9 | asset quantity; 10 | std::string memo; 11 | }; 12 | 13 | void safetransfer (const transfer_args& transfer) { 14 | if (transfer.to != "bank.safesnd"_n) 15 | eosio_exit(0); 16 | 17 | name to = name(transfer.memo); 18 | action( 19 | permission_level{ "bank.safesnd"_n, "active"_n }, 20 | "bank.token", "transfer"_n, 21 | std::make_tuple( "bank.safesnd"_n, to, transfer.quantity, std::string("bank.safesnd") ) 22 | ).send(); 23 | } 24 | 25 | extern "C" { 26 | [[noreturn]] void apply( uint64_t receiver, uint64_t code, uint64_t action ) { 27 | eosio_assert( code == "bank.token"_n.value && action == "transfer"_n.value, "only bank.token transfers permitted"); 28 | safetransfer( unpack_action_data() ); 29 | eosio_exit(0); 30 | } 31 | } -------------------------------------------------------------------------------- /bank.pay2key/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Chris Atanasian and Mason Raasch 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define BOOST_TEST_STATIC_LINK 14 | 15 | void translate_fc_exception(const fc::exception &e) { 16 | std::cerr << "\033[33m" << e.to_detail_string() << "\033[0m" << std::endl; 17 | BOOST_TEST_FAIL("Caught Unexpected Exception"); 18 | } 19 | 20 | boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { 21 | 22 | bool is_verbose = false; 23 | std::string verbose_arg = "--verbose"; 24 | for (int i = 0; i < argc; i++) { 25 | if (verbose_arg == argv[i]) { 26 | is_verbose = true; 27 | break; 28 | } 29 | } 30 | if(!is_verbose) fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::off); 31 | 32 | boost::unit_test::unit_test_monitor.template register_exception_translator(&translate_fc_exception); 33 | 34 | return nullptr; 35 | } 36 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | set(EOSIO_VERSION_MIN "1.6") 4 | set(EOSIO_VERSION_SOFT_MAX "1.8") 5 | #set(EOSIO_VERSION_HARD_MAX "") 6 | 7 | find_package(eosio) 8 | 9 | ### Check the version of eosio 10 | set(VERSION_MATCH_ERROR_MSG "") 11 | EOSIO_CHECK_VERSION(VERSION_OUTPUT "${EOSIO_VERSION}" 12 | "${EOSIO_VERSION_MIN}" 13 | "${EOSIO_VERSION_SOFT_MAX}" 14 | "${EOSIO_VERSION_HARD_MAX}" 15 | VERSION_MATCH_ERROR_MSG) 16 | if(VERSION_OUTPUT STREQUAL "MATCH") 17 | message(STATUS "Using eosio version ${EOSIO_VERSION}") 18 | elseif(VERSION_OUTPUT STREQUAL "WARN") 19 | message(WARNING "Using eosio version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use eosio version ${EOSIO_VERSION_SOFT_MAX}.x") 20 | else() # INVALID OR MISMATCH 21 | message(FATAL_ERROR "Found eosio version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use eosio version ${EOSIO_VERSION_SOFT_MAX}.x") 22 | endif(VERSION_OUTPUT STREQUAL "MATCH") 23 | 24 | 25 | enable_testing() 26 | 27 | configure_file(${CMAKE_SOURCE_DIR}/contracts.hpp.in ${CMAKE_BINARY_DIR}/contracts.hpp) 28 | 29 | include_directories(${CMAKE_BINARY_DIR}) 30 | 31 | file(GLOB UNIT_TESTS "*.cpp" "*.hpp") 32 | 33 | add_eosio_test( unit_test ${UNIT_TESTS} ) 34 | -------------------------------------------------------------------------------- /bank.pay2key/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 15 | 16 | 25 | EOSIO UTXO Frontend 26 | 27 | 28 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(frax_contracts VERSION 1.0.0) 3 | 4 | set(EOSIO_CDT_VERSION_MIN "1.6") 5 | set(EOSIO_CDT_VERSION_SOFT_MAX "1.6") 6 | #set(EOSIO_CDT_VERSION_HARD_MAX "") 7 | 8 | find_package(eosio.cdt) 9 | 10 | ### Check the version of eosio.cdt 11 | set(VERSION_MATCH_ERROR_MSG "") 12 | EOSIO_CHECK_VERSION(VERSION_OUTPUT "${EOSIO_CDT_VERSION}" 13 | "${EOSIO_CDT_VERSION_MIN}" 14 | "${EOSIO_CDT_VERSION_SOFT_MAX}" 15 | "${EOSIO_CDT_VERSION_HARD_MAX}" 16 | VERSION_MATCH_ERROR_MSG) 17 | if(VERSION_OUTPUT STREQUAL "MATCH") 18 | message(STATUS "Using eosio.cdt version ${EOSIO_CDT_VERSION}") 19 | elseif(VERSION_OUTPUT STREQUAL "WARN") 20 | message(WARNING "Using eosio.cdt version ${EOSIO_CDT_VERSION} even though it exceeds the maximum supported version of ${EOSIO_CDT_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use eosio.cdt version ${EOSIO_CDT_VERSION_SOFT_MAX}.x") 21 | else() # INVALID OR MISMATCH 22 | message(FATAL_ERROR "Found eosio.cdt version ${EOSIO_CDT_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use eosio.cdt version ${EOSIO_CDT_VERSION_SOFT_MAX}.x") 23 | endif(VERSION_OUTPUT STREQUAL "MATCH") 24 | 25 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 26 | set(TEST_BUILD_TYPE "Debug") 27 | set(CMAKE_BUILD_TYPE "Release") 28 | else() 29 | set(TEST_BUILD_TYPE ${CMAKE_BUILD_TYPE}) 30 | endif() 31 | 32 | add_subdirectory(frax.loans) 33 | add_subdirectory(frax.reserve) 34 | 35 | if (APPLE) 36 | set(OPENSSL_ROOT "/usr/local/opt/openssl") 37 | elseif (UNIX) 38 | set(OPENSSL_ROOT "/usr/include/openssl") 39 | endif() 40 | set(SECP256K1_ROOT "/usr/local") 41 | 42 | if ("$ENV{NOTEST}" STREQUAL "") 43 | include(UnitTestsExternalProject.txt) 44 | endif() 45 | -------------------------------------------------------------------------------- /tests/token_test_api.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using namespace eosio::testing; 4 | using namespace eosio; 5 | using namespace eosio::chain; 6 | 7 | using mvo = fc::mutable_variant_object; 8 | using action_result = base_tester::action_result; 9 | 10 | class token_test_api { 11 | public: 12 | account_name contract; 13 | 14 | token_test_api(account_name acnt, tester* tester) { 15 | contract = acnt; 16 | _tester = tester; 17 | 18 | _tester->create_accounts({contract}); 19 | _tester->set_code(contract, contracts::token_wasm()); 20 | _tester->set_abi(contract, contracts::token_abi().data()); 21 | 22 | const auto &accnt = _tester->control->db().get(contract); 23 | 24 | abi_def abi; 25 | BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); 26 | abi_ser.set_abi(abi, abi_serializer_max_time); 27 | } 28 | 29 | action_result transfer(const name& from, const name& to, const asset& amount, const string memo = "") 30 | { 31 | return push_action( 32 | from, contract, N(transfer), 33 | mvo()("from", from)("to", to)("quantity", amount)("memo", memo)); 34 | } 35 | 36 | fc::variant get_account(const account_name& acc, const string& symbolname) 37 | { 38 | auto symb = eosio::chain::symbol::from_string(symbolname); 39 | auto symbol_code = symb.to_symbol_code().value; 40 | vector data = _tester->get_row_by_account( contract, acc, N(accounts), symbol_code ); 41 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "account", data, abi_serializer_max_time ); 42 | } 43 | 44 | action_result push_action(const account_name &signer, 45 | const account_name &cnt, 46 | const action_name &name, 47 | const variant_object &data) { 48 | string action_type_name = abi_ser.get_action_type(name); 49 | action act; 50 | act.account = cnt; 51 | act.name = name; 52 | act.data = abi_ser.variant_to_binary(action_type_name, data, abi_serializer_max_time); 53 | 54 | return _tester->push_action(std::move(act), uint64_t(signer)); 55 | } 56 | 57 | private: 58 | abi_serializer abi_ser; 59 | tester* _tester; 60 | fc::microseconds abi_serializer_max_time{1000*1000}; 61 | }; 62 | -------------------------------------------------------------------------------- /bank.price/bank.price.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace eosio; 6 | using namespace std; 7 | 8 | class [[eosio::contract("bank.price")]] bankprice : public contract { 9 | 10 | private: 11 | 12 | struct [[eosio::table]] price_t { 13 | asset price; 14 | uint64_t primary_key() const { return price.symbol.code().raw(); } 15 | }; 16 | 17 | typedef multi_index<"price"_n, price_t> prices_table; 18 | 19 | public: 20 | 21 | using contract::contract; 22 | 23 | ACTION create(asset initprice); 24 | 25 | ACTION update(name updater, asset price); 26 | 27 | }; 28 | 29 | // Table info from eosio.system contract 30 | // Needed to determine top 21 producers 31 | namespace eosiosystem { 32 | struct [[eosio::table, eosio::contract("eosio.system")]] producer_info { 33 | name owner; 34 | double total_votes = 0; 35 | eosio::public_key producer_key; /// a packed public key object 36 | bool is_active = true; 37 | std::string url; 38 | uint32_t unpaid_blocks = 0; 39 | time_point last_claim_time; 40 | uint16_t location = 0; 41 | 42 | uint64_t primary_key()const { return owner.value; } 43 | double by_votes()const { return is_active ? -total_votes : total_votes; } 44 | bool active()const { return is_active; } 45 | void deactivate() { producer_key = public_key(); is_active = false; } 46 | 47 | // explicit serialization macro is not necessary, used here only to improve compilation time 48 | EOSLIB_SERIALIZE( producer_info, (owner)(total_votes)(producer_key)(is_active)(url) 49 | (unpaid_blocks)(last_claim_time)(location) ) 50 | }; 51 | 52 | typedef eosio::multi_index< "producers"_n, producer_info, 53 | indexed_by<"prototalvote"_n, const_mem_fun > 54 | > producers_table; 55 | } 56 | -------------------------------------------------------------------------------- /bank.cdp/bank.cdp.contracts.md: -------------------------------------------------------------------------------- 1 |

bail

2 | Reclaims collateral from an overcollateralized cdp, without taking the cdp below its liquidation ratio. 3 |

close

4 | Close balance of given symbol for account. 5 |

deposit

6 | Description of the deposit function 7 |

draw

8 | Issue fresh stablecoin from this cdp. 9 |

liquify

10 | If the collateral value in a CDP drops below 150% of the outstanding stablecoin, the contract automatically sells enough of your collateral to buy back as many stablecoin as you issued. The issued stablecoin is thus taken out of circulation. Similar to a margin call. 11 |

lock

12 | Unless CDP is in liquidation, its owner can use lock to lock more collateral. 13 |

open

14 | Open cdp or initiate balances for account. 15 |

propose

16 | Publish a proposal that either motions for the enactment of a new cdp type, or modification of an existing one. 17 |

referended

18 | Called either automatically after VOTE_PERIOD from the moment of proposal via "propose", via deferred action with proposer's auth, or (if deferred action fails) may be called directly by proposer after VOTE_PERIOD has passed. Proposal may be enacted if there are more votes in favor than against. Cleanup must be done regardless on relevant multi_index tables. 19 |

settle

20 | The system uses the market price of collateral at the time of settlement to compute how much collateral each user gets. 21 |

shut

22 | Owner can close this CDP, if the price feed is up to date and the CDP is not in liquidation. Reclaims all collateral and cancels all issuance plus fee. 23 |

transfer

24 | Transfer stablecoin 25 |

upfeed

26 | Price feed data update action. 27 |

vote

28 | Take a position (for/against) on a cdp proposal 29 |

wipe

30 | Owner can send back stablecoin and reduce the cdp's issued stablecoin balance. 31 |

withdraw

32 | Description of the withdraw function 33 | -------------------------------------------------------------------------------- /tests/pay2key.sign.js: -------------------------------------------------------------------------------- 1 | const ecc = require('eosjs-ecc'); 2 | const base58 = require('bs58'); 3 | 4 | // due to JS limitaitons, this only has 48-bit precision, 5 | // but that's good enough for what we need 6 | function uint64_to_little_endian(num) { 7 | const buf = Buffer.alloc(8); 8 | buf.writeUIntLE(num, 0, 6); 9 | return buf; 10 | } 11 | 12 | function uint32_to_little_endian(num) { 13 | const buf = Buffer.alloc(4); 14 | buf.writeUIntLE(num, 0, 4); 15 | return buf; 16 | } 17 | 18 | function sign(chain_id, from, to, amount, fee, nonce, memo, privkey) { 19 | const version = 2; 20 | const length = 96 + memo.length; 21 | 22 | const chainidBuf = uint32_to_little_endian(chain_id); 23 | const pkeyFrom = base58.decode(from.substring(3)); 24 | const pkeyTo = base58.decode(to.substring(3)); 25 | const amountBuf = uint64_to_little_endian(amount); 26 | const feeBuf = uint64_to_little_endian(fee); 27 | const nonceBuf = uint64_to_little_endian(nonce); 28 | const memoBuf = Buffer.from(memo); 29 | 30 | // create raw tx 31 | const buffer = Buffer.alloc(length); 32 | buffer[0] = version; 33 | buffer[1] = length; 34 | chainidBuf.copy(buffer, 2, 0, 4); 35 | pkeyFrom.copy(buffer, 6, 0, 33); 36 | pkeyTo.copy(buffer, 39, 0, 33); 37 | amountBuf.copy(buffer, 72, 0, 8); 38 | feeBuf.copy(buffer, 80, 0, 8); 39 | nonceBuf.copy(buffer, 88, 0, 8); 40 | memoBuf.copy(buffer, 96, 0, memoBuf.length); 41 | //console.log(buffer.toString('hex')); 42 | 43 | // hash raw tx 44 | const hashed = ecc.sha256(buffer, 'hex'); 45 | //console.log(hashed); 46 | 47 | // sign transaction 48 | const sig = ecc.signHash(hashed, privkey); 49 | 50 | return sig; 51 | } 52 | 53 | /////////////////////////////// 54 | // Main Execution Thread 55 | if (process.argv.length != 10) { 56 | console.log(` 57 | USAGE: node pay2key.sign.js [chain_id] [from] [to] [amount] [fee] [nonce] [memo] [privkey] 58 | Example: node pay2key.sign.js 0 EOS7PoGq46ssqeGh8ZNScWQxqbwg5RNvLAwVw3i5dQcZ3a1h9nRyr EOS6KnJPV1mDuS8pYuLucaWzkwbWjGPeJsfQDpqc7NZ4F7zTQh4Wt 10000 10 1 "token transfer" 5KQRA6BBHEHSbmvio3S9oFfVERvv79XXppmYExMouSBqPkZTD79 59 | `); 60 | } 61 | else { 62 | const args = process.argv.slice(2); 63 | console.log(sign(...args)); 64 | } 65 | -------------------------------------------------------------------------------- /bank.price/bank.price.cpp: -------------------------------------------------------------------------------- 1 | #include "bank.price.hpp" 2 | 3 | // Create a new price to track 4 | [[eosio::action]] 5 | void bankprice::create(asset initprice) { 6 | // Auth check 7 | require_auth( _self ); 8 | 9 | // Validate the initprice asset 10 | auto sym = initprice.symbol; 11 | eosio_assert( sym.is_valid(), "invalid symbol name" ); 12 | eosio_assert( initprice.is_valid(), "invalid initprice"); 13 | eosio_assert( initprice.amount > 0, "initprice must be positive"); 14 | 15 | // Make sure the symbol is not already being tracked 16 | prices_table pricetable( _self, _self.value ); 17 | auto existing = pricetable.find( sym.code().raw() ); 18 | eosio_assert( existing == pricetable.end(), "price with symbol already exists" ); 19 | 20 | // Create an entry for the symbol 21 | pricetable.emplace( _self, [&]( auto& p ) { 22 | p.price = initprice; 23 | }); 24 | } 25 | 26 | // Update the price for a symbol 27 | [[eosio::action]] 28 | void bankprice::update(name updater, asset price) { 29 | // Auth check 30 | require_auth(updater); 31 | 32 | // Validate inputs 33 | eosio_assert( price.is_valid(), "invalid price" ); 34 | eosio_assert( price.amount > 0, "must update with positive price" ); 35 | 36 | // Get producer vote info 37 | eosiosystem::producers_table producers(name("eosio"), name("eosio").value); 38 | auto votes_idx = producers.get_index(); 39 | auto vote_it = votes_idx.end(); 40 | 41 | // Make sure producer is in top 21 42 | uint8_t loop = 0; 43 | bool isTop21 = false; 44 | while(vote_it != votes_idx.begin() && loop < 21) { 45 | if (vote_it->owner == updater) { 46 | isTop21 = true; 47 | break; 48 | } 49 | } 50 | eosio_assert(isTop21, "Producer must be in top 21"); 51 | 52 | // Get price info 53 | prices_table pricetable( _self, _self.value ); 54 | auto current_price = pricetable.get(price.symbol.code().raw(), "Symbol does not exist. Create it first"); 55 | eosio_assert( current_price.price.symbol == price.symbol, "Symbol precision mismatch" ); 56 | 57 | // Calculate updated price info 58 | uint64_t new_price = current_price.price.amount * 9 / 10 + price.amount / 10; 59 | 60 | // Update table 61 | pricetable.modify( current_price, _self, [&]( auto& p ) { 62 | p.price.amount = new_price; 63 | }); 64 | 65 | } 66 | EOSIO_DISPATCH( bankprice, (create)(update)) 67 | -------------------------------------------------------------------------------- /frax.reserve/frax.reserve.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace eosio; 7 | using namespace std; 8 | 9 | const symbol FRAX_SYMBOL = symbol(symbol_code("FRAX"), 4); 10 | const symbol FXS_SYMBOL = symbol(symbol_code("FXS"), 4); 11 | const symbol USDT_SYMBOL = symbol(symbol_code("USDT"), 4); 12 | 13 | class [[eosio::contract("frax.reserve")]] fraxreserve : public contract { 14 | 15 | public: 16 | using contract::contract; 17 | 18 | [[eosio::action]] 19 | void addtoken(name contract, symbol ticker); 20 | 21 | [[eosio::action]] 22 | void buyfrax(name buyer, asset frax); 23 | 24 | [[eosio::action]] 25 | void settarget(asset reserve_usdt, asset reserve_fxs, uint64_t fxs_price); 26 | 27 | // Public but not a directly callable action 28 | // Called indirectly by sending EOS to this contract 29 | void deposit( name from, name to, asset quantity, string memo ); 30 | 31 | // Deposits table 32 | // Scoped by user 33 | struct [[eosio::table]] account { 34 | asset balance; 35 | 36 | uint64_t primary_key() const { return balance.symbol.raw(); } 37 | }; 38 | typedef eosio::multi_index<"accounts"_n, account> accounts; 39 | 40 | // Token stats 41 | // Contract scope 42 | struct [[eosio::table]] stats_t { 43 | asset supply; 44 | name contract; 45 | 46 | uint64_t primary_key() const { return supply.symbol.raw(); } 47 | uint64_t by_contract() const { return contract.value; } 48 | uint128_t by_contract_symbol() const { return merge_contract_symbol(contract, supply.symbol); } 49 | }; 50 | typedef eosio::multi_index<"stats"_n, stats_t, 51 | indexed_by<"bycontract"_n, const_mem_fun>, 52 | indexed_by<"byctrsym"_n, const_mem_fun> 53 | > stats; 54 | 55 | // System parameters 56 | // Singleton - Contract scope 57 | struct [[eosio::table]] params_t { 58 | asset target_usdt; 59 | asset target_fxs; 60 | uint64_t fxs_price; // (FXS / USDT) * 1e4. Ex: $20 FXS. Set to 20e4 61 | 62 | uint64_t primary_key() const { return 1; } // constant primary key forces singleton 63 | }; 64 | typedef eosio::multi_index<"sysparams"_n, params_t > sysparams; 65 | 66 | private: 67 | 68 | static uint128_t merge_contract_symbol( name contract, symbol sym ) { 69 | uint128_t merged; 70 | uint64_t raw_sym = sym.raw(); 71 | memcpy((uint8_t *)&merged, (uint8_t *)&contract.value, 8); 72 | memcpy((uint8_t *)&merged + 8, (uint8_t *)&raw_sym, 8); 73 | return merged; 74 | } 75 | 76 | }; 77 | -------------------------------------------------------------------------------- /tests/test_contracts/eosio.token/eosio.token.abi: -------------------------------------------------------------------------------- 1 | { 2 | "version": "eosio::abi/1.0", 3 | "types": [{ 4 | "new_type_name": "account_name", 5 | "type": "name" 6 | }], 7 | "structs": [{ 8 | "name": "transfer", 9 | "base": "", 10 | "fields": [ 11 | {"name":"from", "type":"account_name"}, 12 | {"name":"to", "type":"account_name"}, 13 | {"name":"quantity", "type":"asset"}, 14 | {"name":"memo", "type":"string"} 15 | ] 16 | },{ 17 | "name": "create", 18 | "base": "", 19 | "fields": [ 20 | {"name":"issuer", "type":"account_name"}, 21 | {"name":"maximum_supply", "type":"asset"} 22 | ] 23 | },{ 24 | "name": "issue", 25 | "base": "", 26 | "fields": [ 27 | {"name":"to", "type":"account_name"}, 28 | {"name":"quantity", "type":"asset"}, 29 | {"name":"memo", "type":"string"} 30 | ] 31 | },{ 32 | "name": "retire", 33 | "base": "", 34 | "fields": [ 35 | {"name":"quantity", "type":"asset"}, 36 | {"name":"memo", "type":"string"} 37 | ] 38 | },{ 39 | "name": "close", 40 | "base": "", 41 | "fields": [ 42 | {"name":"owner", "type":"account_name"}, 43 | {"name":"symbol", "type":"symbol"} 44 | ] 45 | },{ 46 | "name": "account", 47 | "base": "", 48 | "fields": [ 49 | {"name":"balance", "type":"asset"} 50 | ] 51 | },{ 52 | "name": "currency_stats", 53 | "base": "", 54 | "fields": [ 55 | {"name":"supply", "type":"asset"}, 56 | {"name":"max_supply", "type":"asset"}, 57 | {"name":"issuer", "type":"account_name"} 58 | ] 59 | } 60 | ], 61 | "actions": [{ 62 | "name": "transfer", 63 | "type": "transfer", 64 | "ricardian_contract": "" 65 | },{ 66 | "name": "issue", 67 | "type": "issue", 68 | "ricardian_contract": "" 69 | },{ 70 | "name": "retire", 71 | "type": "retire", 72 | "ricardian_contract": "" 73 | }, { 74 | "name": "create", 75 | "type": "create", 76 | "ricardian_contract": "" 77 | }, { 78 | "name": "close", 79 | "type": "close", 80 | "ricardian_contract": "" 81 | } 82 | 83 | ], 84 | "tables": [{ 85 | "name": "accounts", 86 | "type": "account", 87 | "index_type": "i64", 88 | "key_names" : ["currency"], 89 | "key_types" : ["uint64"] 90 | },{ 91 | "name": "stat", 92 | "type": "currency_stats", 93 | "index_type": "i64", 94 | "key_names" : ["currency"], 95 | "key_types" : ["uint64"] 96 | } 97 | ], 98 | "ricardian_clauses": [], 99 | "abi_extensions": [] 100 | } 101 | -------------------------------------------------------------------------------- /tests/fraxloans_api.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using namespace eosio::testing; 4 | using namespace eosio; 5 | using namespace eosio::chain; 6 | 7 | using mvo = fc::mutable_variant_object; 8 | using action_result = base_tester::action_result; 9 | 10 | class fraxloans_api { 11 | public: 12 | account_name contract; 13 | 14 | fraxloans_api(account_name acnt, tester* tester) { 15 | contract = acnt; 16 | _tester = tester; 17 | 18 | _tester->create_accounts({contract}); 19 | _tester->set_code(contract, contracts::fraxloans_wasm()); 20 | _tester->set_abi(contract, contracts::fraxloans_abi().data()); 21 | 22 | const auto &accnt = _tester->control->db().get(contract); 23 | 24 | abi_def abi; 25 | BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); 26 | abi_ser.set_abi(abi, abi_serializer_max_time); 27 | } 28 | 29 | action_result addtoken(const name& token_contract, string symb) 30 | { 31 | auto ticker = eosio::chain::symbol::from_string(symb); 32 | return push_action( 33 | contract, contract, N(addtoken), 34 | mvo()("contract", token_contract)("ticker", ticker)); 35 | } 36 | 37 | action_result borrow(const name& borrower, asset quantity) 38 | { 39 | return push_action( 40 | borrower, contract, N(borrow), 41 | mvo()("borrower", borrower)("quantity", quantity)); 42 | } 43 | 44 | action_result setprice(asset price) 45 | { 46 | return push_action( 47 | contract, contract, N(setprice), 48 | mvo()("price", price)); 49 | } 50 | 51 | fc::variant get_account(const account_name& acc, const string& symbolname) 52 | { 53 | auto symb = eosio::chain::symbol::from_string(symbolname); 54 | auto symbol_code = symb.to_symbol_code().value; 55 | vector data = _tester->get_row_by_account( contract, acc, N(accounts), symbol_code ); 56 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "account", data, abi_serializer_max_time ); 57 | } 58 | 59 | fc::variant get_tokenstats(const string& symbolname) 60 | { 61 | auto symb = eosio::chain::symbol::from_string(symbolname); 62 | auto symbol_code = symb.to_symbol_code().value; 63 | vector data = _tester->get_row_by_account( contract, contract, N(tokenstats), symbol_code ); 64 | 65 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "stats_t", data, abi_serializer_max_time ); 66 | } 67 | 68 | action_result push_action(const account_name &signer, 69 | const account_name &cnt, 70 | const action_name &name, 71 | const variant_object &data) { 72 | string action_type_name = abi_ser.get_action_type(name); 73 | action act; 74 | act.account = cnt; 75 | act.name = name; 76 | act.data = abi_ser.variant_to_binary(action_type_name, data, abi_serializer_max_time); 77 | 78 | return _tester->push_action(std::move(act), uint64_t(signer)); 79 | } 80 | 81 | private: 82 | abi_serializer abi_ser; 83 | tester* _tester; 84 | fc::microseconds abi_serializer_max_time{1000*1000}; 85 | }; 86 | -------------------------------------------------------------------------------- /bank.pay2key/frontend/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /frax.loans/frax.loans.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace eosio; 7 | using namespace std; 8 | 9 | class [[eosio::contract("frax.loans")]] fraxloans : public contract { 10 | 11 | public: 12 | using contract::contract; 13 | 14 | // Constants 15 | const symbol FRAX_SYMBOL = symbol(symbol_code("FRAX"), 4); 16 | const symbol FXS_SYMBOL = symbol(symbol_code("FXS"), 4); 17 | const symbol USDT_SYMBOL = symbol(symbol_code("USDT"), 4); 18 | const double COLLATERAL_RATIO = 0.75; // Can only borrow upto 75% of collateral 19 | 20 | [[eosio::action]] 21 | void addtoken(name contract, symbol ticker); 22 | 23 | [[eosio::action]] 24 | void borrow(name borrower, asset quantity); 25 | 26 | [[eosio::action]] 27 | void repay(name borrower, asset quantity); 28 | 29 | [[eosio::action]] 30 | void setprice(asset price); 31 | 32 | //[[eosio::action]] 33 | //void liquidate(name user, name executor); 34 | 35 | [[eosio::on_notify("tmp::tmp")]] void tmp() { } // temp hack. required to make on_notify work until bug is patched 36 | 37 | [[eosio::on_notify("*::transfer")]] 38 | void deposit( name from, name to, asset quantity, string memo ); 39 | 40 | // Deposits table 41 | // Scoped by user 42 | struct [[eosio::table]] account { 43 | asset balance; 44 | asset borrowing; 45 | uint64_t last_updated; 46 | 47 | uint64_t primary_key() const { return balance.symbol.code().raw(); } 48 | }; 49 | typedef eosio::multi_index<"accounts"_n, account> accounts; 50 | 51 | // Token stats 52 | // Contract scope 53 | struct [[eosio::table]] stats_t { 54 | asset available; 55 | asset loaned; 56 | name contract; 57 | asset price; // 4 decimal places, prices in USDT 58 | bool allowed_as_collateral; 59 | bool can_deposit; 60 | uint64_t interest_counter; 61 | 62 | uint64_t primary_key() const { return available.symbol.code().raw(); } 63 | uint64_t by_contract() const { return contract.value; } 64 | uint128_t by_contract_symbol() const { return merge_contract_symbol(contract, available.symbol); } 65 | }; 66 | typedef eosio::multi_index<"tokenstats"_n, stats_t, 67 | indexed_by<"bycontract"_n, const_mem_fun>, 68 | indexed_by<"byctrsym"_n, const_mem_fun> 69 | > stats; 70 | 71 | // System parameters 72 | // Singleton - Contract scope 73 | struct [[eosio::table]] params_t { 74 | 75 | uint64_t primary_key() const { return 1; } // constant primary key forces singleton 76 | }; 77 | typedef eosio::multi_index<"sysparams"_n, params_t > sysparams; 78 | 79 | private: 80 | 81 | static uint128_t merge_contract_symbol( name contract, symbol sym ) { 82 | uint128_t merged; 83 | uint64_t raw_sym = sym.raw(); 84 | memcpy((uint8_t *)&merged, (uint8_t *)&contract.value, 8); 85 | memcpy((uint8_t *)&merged + 8, (uint8_t *)&raw_sym, 8); 86 | return merged; 87 | } 88 | 89 | }; 90 | -------------------------------------------------------------------------------- /bank.pay2key/bank.pay2key.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////// 2 | // COMPILED WTIH EOSIO.CDT 1.6.1 3 | /////////////////////////////////////// 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace eosio; 11 | using namespace std; 12 | 13 | const std::string WITHDRAW_ADDRESS = "EOS1111111111111111111111111111111114T1Anm"; 14 | uint8_t WITHDRAW_KEY_BYTES[37] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 231, 181, 34 }; 15 | 16 | class [[eosio::contract("bank.pay2key")]] pay2key : public contract { 17 | 18 | public: 19 | using contract::contract; 20 | 21 | [[eosio::action]] 22 | void create(name token_contract, symbol ticker); 23 | 24 | [[eosio::action]] 25 | void transfer( 26 | uint64_t chain_id, 27 | name relayer_account, 28 | public_key relayer, 29 | public_key from, 30 | public_key to, 31 | asset amount, 32 | asset fee, 33 | uint64_t nonce, 34 | string memo, 35 | signature sig); 36 | 37 | // Public but not a directly callable action 38 | // Called indirectly by sending EOS to this contract 39 | void issue( name from, name to, asset quantity, string memo ); 40 | 41 | struct [[eosio::table]] account { 42 | uint64_t key; 43 | public_key publickey; 44 | asset balance; 45 | uint64_t last_nonce; 46 | 47 | uint64_t primary_key() const { return key; } 48 | fixed_bytes<32> bypk() const { 49 | return public_key_to_fixed_bytes(publickey); 50 | }; 51 | }; 52 | 53 | struct [[eosio::table]] currstats { 54 | uint64_t chain_id; 55 | asset supply; 56 | name token_contract; 57 | eosio::symbol symbol; 58 | 59 | uint64_t primary_key() const { return chain_id; } 60 | uint64_t by_token_contract() const { return token_contract.value; } 61 | uint128_t by_contract_symbol() const { return merge_contract_symbol(token_contract, symbol); } 62 | }; 63 | 64 | typedef eosio::multi_index<"accounts"_n, 65 | account, 66 | indexed_by<"bypk"_n, const_mem_fun, &account::bypk>> 67 | > accounts; 68 | 69 | typedef eosio::multi_index<"stats"_n, currstats, 70 | indexed_by<"bycontract"_n, const_mem_fun>, 71 | indexed_by<"byctrsym"_n, const_mem_fun> 72 | > stats; 73 | 74 | private: 75 | 76 | static fixed_bytes<32> public_key_to_fixed_bytes(const public_key publickey) { 77 | return sha256(publickey.data.begin(), 33); 78 | } 79 | 80 | void sub_balance(uint64_t chain_id, public_key sender, asset value); 81 | 82 | void add_balance(uint64_t chain_id, public_key recipient, asset value, name ram_payer); 83 | 84 | static uint128_t merge_contract_symbol( name contract, symbol sym ) { 85 | uint128_t merged; 86 | uint64_t raw_sym = sym.raw(); 87 | memcpy((uint8_t *)&merged, (uint8_t *)&contract.value, 8); 88 | memcpy((uint8_t *)&merged + 8, (uint8_t *)&raw_sym, 8); 89 | return merged; 90 | } 91 | 92 | }; 93 | -------------------------------------------------------------------------------- /bank.shares/bank.shares.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace eosio; 6 | using namespace std; 7 | 8 | const name SYS_TOKEN_NAME = "BANK"_n; 9 | 10 | class [[eosio::contract("bank.shares")]] bankshares : public contract { 11 | public: 12 | using contract::contract; 13 | 14 | // Return type for the updater function 15 | struct AuctionPack { 16 | auto _it; 17 | auctions _tbl; 18 | } 19 | 20 | // -------------STRUCTS------------- 21 | // List of auctions 22 | struct [[eosio::table]] auction { 23 | uint64_t id; 24 | asset issue; // Amount of SYS_TOKEN_NAME being issued 25 | asset iss_remain; // SYS_TOKEN_NAME left to be sold 26 | asset current_ask; // Current asking price for 1 SYS_TOKEN_NAME, in CURR 27 | asset ask_floor; // Minimum asking price for 1 SYS_TOKEN_NAME that you are willing to accept, in CURR 28 | time_point start_time; // Starting time of the auction 29 | time_point end_time; // Ending time of the auction 30 | 31 | uint64_t primary_key() const { return id; } 32 | symbol get_symbol () const { return ask_floor.symbol; } 33 | }; 34 | 35 | // -------------ACTIONS------------- 36 | [[eosio::action]] 37 | startauction( 38 | asset quantity, // Amount of SYS_TOKEN_NAME being issued 39 | asset askstart, // Starting asking price for 1 SYS_TOKEN_NAME, in CURR 40 | asset askfloor, // Minimum asking price for 1 SYS_TOKEN_NAME that you are willing to accept, in CURR 41 | string memo, // A memo 42 | time_point end_time // The ending time, in epoch milliseconds 43 | ); 44 | 45 | [[eosio::action]] 46 | updateask( 47 | uint64_t auctionid // The id of the auction 48 | ); 49 | 50 | [[eosio::action]] 51 | buyshares( 52 | uint64_t auctionid, // ID of the auction you want to participate in 53 | name buyer, // The name of you, the buyer 54 | asset buyamount, // The amount of SYS_TOKEN_NAME that you want to buy 55 | asset maxbid // The maximum price per 1 SYS_TOKEN_NAME that you are willing to pay, in CURR 56 | ); 57 | 58 | // --------TABLE DEFINITIONS-------- 59 | typedef eosio::multi_index<"auctions"_n, auction, 60 | indexed_by< "bypk", const_mem_fun>, 61 | indexed_by< "bysymbol", const_mem_fun> 62 | > auctions; 63 | 64 | private: 65 | // Update the bid internally 66 | AuctionPack update_ask_local(uint64_t auctionid); 67 | }; 68 | 69 | // Table info from bank.token contract. Needed for the auction and various other things. 70 | namespace banktoken { 71 | 72 | struct [[eosio::table, eosio::contract("bank.token")]] account { 73 | asset balance; 74 | 75 | uint64_t primary_key()const { return balance.symbol.code().raw(); } 76 | }; 77 | 78 | struct [[eosio::table, eosio::contract("bank.token")]] currency_stats { 79 | asset supply; 80 | asset max_supply; 81 | name issuer; 82 | 83 | uint64_t primary_key()const { return supply.symbol.code().raw(); } 84 | }; 85 | typedef eosio::multi_index<"accounts"_n, account> accounts; 86 | typedef eosio::multi_index<"stats"_n, currency_stats> stats; 87 | } -------------------------------------------------------------------------------- /bank.cdp/README.md: -------------------------------------------------------------------------------- 1 | 2 | ###### Future note: some of the information herein should be apt for re-organization into the relevant Ricardian clauses of the bank.cdp contract ABI 3 | 4 | # Design Decisions 5 | 6 | * If you'd like your CDP to dip below the agreed upon liqidation ratio of your CDP's type, via one of the relevant actions (draw or bail), then TOO BAD because you won't be permitted (you'll hit an assertion). 7 | * If you'd like to liquidate your own CDP in the event of significant price slippage, then TOO BAD because that would let you print free money and we won't have that kind of behavior here (unless you collude with another account). 8 | 9 | # Differences between cdpEOS (aka bank.cdp) and cdpETH (aka MakerDAO) 10 | 11 | bank.cdp successfully implements multi-collateral CDPs by accepting any eosio.token, and the entire protocol is implemented via only 15 distinct functions, and just over 800 SLOC. 12 | 13 | The major discrepancy between the two protocols is in how 14 | liquidation auctions, stability fees, and governance are handled. Nonetheless, there are many concepts in common, such as the fact that liquidation may (and should) operate effectively in the absence of price feeds. 15 | 16 | To provide for better liquidity, Maker uses simultaneous (parallel) auctions of four types: 17 | 18 | * #1 Stablecoin (stable token) bids for collateral 19 | * #2 Reverse dutch of the above (collateral bids for stablecoin) in the event of some collateral remaining to be refunded to a CDP owner. 20 | * #3 Stablecoin bids for MKR (voting token) in the event of balance shortage in #1 (not enough stablecoin was raised) 21 | * #4 MKR bids for stablecoin in the event of balance surplus in #1 (too much stablecoin was raised) 22 | 23 | Auction #2 is omitted entirely from our protocol: we do not endorse it because CDP owners should be playing it safe and overcollateralizing even more. The rest of the phases are executed in sequence rather than in parallel. 24 | 25 | Unlike in Ethereum where the primary constraint is speed and gas, with faster block times the main constraint in EOS is RAM so our approach was taken from the angle of a more space efficient implementation, and a simpler view of the computation overall. 26 | 27 | On that last note, we also omit the calculation of stability fees on a global basis as in multi-collateral stablecoin (whenever debt is being taken on or repaid, the fee is minted into the contract's balance and incremented onto a CDP's debt), in favor of an APR-based deduction in VTO upon every wipe action executed on a CDP (closer to single-collateral stablecoin). Moreover, our voting and referendum procedure has a very common sense nature: 28 | 29 | Any account may create a proposal, and as many varying proposals as desired, but we do constrain proposals per CDP type. Only one proposal may be active (in voting) per CDP type (new or modification of existing). 30 | 31 | Voters may vote with their tokens as much as they please (a la Maker) and even post two postions simultaneously (both for and against). 32 | 33 | All voting tokens are refunded to voters upon the expiration of the voting period for a proposal, and if there is a tie between total for and against positions, another voting period is scheduled to take place immediately. 34 | 35 | Global settlement is subjected to popular vote like any CDP change or creation proposal, rather than designated to a select group of Keepers as in MakerDAO. 36 | 37 | Global constants are the designated accounts that provide price feeds, the voting period of 2 weeks for proposals, and the minimum age of 5 minutes (how recent) for price data that is considered acceptable. 38 | 39 | ###### TODO 40 | medium.com/makerdao/dai-reward-rate-earn-a-reward-from-holding-dai-10a07f52f3cf -------------------------------------------------------------------------------- /frax.reserve/frax.reserve.abi: -------------------------------------------------------------------------------- 1 | { 2 | "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", 3 | "version": "eosio::abi/1.1", 4 | "types": [], 5 | "structs": [ 6 | { 7 | "name": "account", 8 | "base": "", 9 | "fields": [ 10 | { 11 | "name": "balance", 12 | "type": "asset" 13 | } 14 | ] 15 | }, 16 | { 17 | "name": "addtoken", 18 | "base": "", 19 | "fields": [ 20 | { 21 | "name": "contract", 22 | "type": "name" 23 | }, 24 | { 25 | "name": "ticker", 26 | "type": "symbol" 27 | } 28 | ] 29 | }, 30 | { 31 | "name": "buyfrax", 32 | "base": "", 33 | "fields": [ 34 | { 35 | "name": "buyer", 36 | "type": "name" 37 | }, 38 | { 39 | "name": "frax", 40 | "type": "asset" 41 | } 42 | ] 43 | }, 44 | { 45 | "name": "params_t", 46 | "base": "", 47 | "fields": [ 48 | { 49 | "name": "target_usdt", 50 | "type": "asset" 51 | }, 52 | { 53 | "name": "target_fxs", 54 | "type": "asset" 55 | }, 56 | { 57 | "name": "fxs_price", 58 | "type": "uint64" 59 | } 60 | ] 61 | }, 62 | { 63 | "name": "settarget", 64 | "base": "", 65 | "fields": [ 66 | { 67 | "name": "reserve_usdt", 68 | "type": "asset" 69 | }, 70 | { 71 | "name": "reserve_fxs", 72 | "type": "asset" 73 | }, 74 | { 75 | "name": "fxs_price", 76 | "type": "uint64" 77 | } 78 | ] 79 | }, 80 | { 81 | "name": "stats_t", 82 | "base": "", 83 | "fields": [ 84 | { 85 | "name": "supply", 86 | "type": "asset" 87 | }, 88 | { 89 | "name": "contract", 90 | "type": "name" 91 | } 92 | ] 93 | } 94 | ], 95 | "actions": [ 96 | { 97 | "name": "addtoken", 98 | "type": "addtoken", 99 | "ricardian_contract": "" 100 | }, 101 | { 102 | "name": "buyfrax", 103 | "type": "buyfrax", 104 | "ricardian_contract": "" 105 | }, 106 | { 107 | "name": "settarget", 108 | "type": "settarget", 109 | "ricardian_contract": "" 110 | } 111 | ], 112 | "tables": [ 113 | { 114 | "name": "accounts", 115 | "type": "account", 116 | "index_type": "i64", 117 | "key_names": [], 118 | "key_types": [] 119 | }, 120 | { 121 | "name": "stats", 122 | "type": "stats_t", 123 | "index_type": "i64", 124 | "key_names": [], 125 | "key_types": [] 126 | }, 127 | { 128 | "name": "sysparams", 129 | "type": "params_t", 130 | "index_type": "i64", 131 | "key_names": [], 132 | "key_types": [] 133 | } 134 | ], 135 | "ricardian_clauses": [], 136 | "variants": [] 137 | } -------------------------------------------------------------------------------- /bank.pay2key/bank.pay2key.abi: -------------------------------------------------------------------------------- 1 | { 2 | "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", 3 | "version": "eosio::abi/1.1", 4 | "types": [], 5 | "structs": [ 6 | { 7 | "name": "account", 8 | "base": "", 9 | "fields": [ 10 | { 11 | "name": "key", 12 | "type": "uint64" 13 | }, 14 | { 15 | "name": "publickey", 16 | "type": "public_key" 17 | }, 18 | { 19 | "name": "balance", 20 | "type": "asset" 21 | }, 22 | { 23 | "name": "last_nonce", 24 | "type": "uint64" 25 | } 26 | ] 27 | }, 28 | { 29 | "name": "create", 30 | "base": "", 31 | "fields": [ 32 | { 33 | "name": "token_contract", 34 | "type": "name" 35 | }, 36 | { 37 | "name": "ticker", 38 | "type": "symbol" 39 | } 40 | ] 41 | }, 42 | { 43 | "name": "currstats", 44 | "base": "", 45 | "fields": [ 46 | { 47 | "name": "chain_id", 48 | "type": "uint64" 49 | }, 50 | { 51 | "name": "supply", 52 | "type": "asset" 53 | }, 54 | { 55 | "name": "token_contract", 56 | "type": "name" 57 | }, 58 | { 59 | "name": "symbol", 60 | "type": "symbol" 61 | } 62 | ] 63 | }, 64 | { 65 | "name": "transfer", 66 | "base": "", 67 | "fields": [ 68 | { 69 | "name": "chain_id", 70 | "type": "uint64" 71 | }, 72 | { 73 | "name": "relayer_account", 74 | "type": "name" 75 | }, 76 | { 77 | "name": "relayer", 78 | "type": "public_key" 79 | }, 80 | { 81 | "name": "from", 82 | "type": "public_key" 83 | }, 84 | { 85 | "name": "to", 86 | "type": "public_key" 87 | }, 88 | { 89 | "name": "amount", 90 | "type": "asset" 91 | }, 92 | { 93 | "name": "fee", 94 | "type": "asset" 95 | }, 96 | { 97 | "name": "nonce", 98 | "type": "uint64" 99 | }, 100 | { 101 | "name": "memo", 102 | "type": "string" 103 | }, 104 | { 105 | "name": "sig", 106 | "type": "signature" 107 | } 108 | ] 109 | } 110 | ], 111 | "actions": [ 112 | { 113 | "name": "create", 114 | "type": "create", 115 | "ricardian_contract": "" 116 | }, 117 | { 118 | "name": "transfer", 119 | "type": "transfer", 120 | "ricardian_contract": "" 121 | } 122 | ], 123 | "tables": [ 124 | { 125 | "name": "accounts", 126 | "type": "account", 127 | "index_type": "i64", 128 | "key_names": [], 129 | "key_types": [] 130 | }, 131 | { 132 | "name": "stats", 133 | "type": "currstats", 134 | "index_type": "i64", 135 | "key_names": [], 136 | "key_types": [] 137 | } 138 | ], 139 | "ricardian_clauses": [], 140 | "variants": [] 141 | } -------------------------------------------------------------------------------- /bank.pay2key/README.md: -------------------------------------------------------------------------------- 1 | # eosio.pay2key 2 | 3 | The UTXO token contract (also called Pay 2 Key contract) is a standardized EOSIO smart contract, which allows token transacting using only public-private key pairs without the need for an EOSIO account or system action. It is similar in feature to the Bitcoin transaction system. To move tokens in a UTXO based contract, an owner only needs the corresponding private key to the public key. A transaction fee is also paid to move the token. A "relayer" with an EOS account (can be a block producer or any individual account) accepts the fee then relays the signed UTXO message to the contract and updates the balance of the appropriate public key. A relayer is similar to a Bitcoin miner in that they update the state of the UTXO contract by appending the signed UTXO transaction to the contract database. 4 | 5 | There are 4 main actions in the contract: 1. Creating the UTXO token specs when the contract is first deployed 2. Sending tokens from EOS accounts to a public key in the Pay2Key contract 3. Transacting UTXO/Pay2Key tokens between public keys 4. Withdrawing your UTXOs from a public key back into an EOS account 6 | 7 | ## 1. Creating a token with a maximum supply 8 | 9 | Before you are able to issue a token to a public key, you must create the spendable output and give the token maximum supply to set up the contract. In this documentation, the ticker of the example token in this documentation is IQ with the Pay2Key ticker as IQUTXO. 10 | 11 | ``` 12 | cleos push action {UTXO_contract_account} create \'["IQUTXO", "100.0000 IQUTXO"]\' -p {UTXO_contract_account} 13 | ``` 14 | 15 | ## 2. Transferring tokens to issue the UTXO 16 | 17 | Anyone can send the designated token to the UTXO contract, triggering an issuance to the public key of their choosing. 18 | ``` 19 | cleos push action everipediaiq transfer '["{EOS_account}", "{UTXO_contract_account}", "100.000 IQUTXO", "{PUBLIC_KEY}"]' -p {EOS_account}@active 20 | ``` 21 | Now that public key will have 100 IQUTXO to spend 22 | 23 | ## 3. Transferring from one public key to another 24 | 25 | To transfer from one public key to another, the transaction must be signed using your private key. For details of how to generate the signature, check out the code in frontend section. The frontend client makes generating this signature easy. There are a number of hosted solutions for UTXO front ends coming. 26 | 27 | ``` 28 | cleos push action utxo transfer '["RELAYER_PUBLIC_KEY", "PUBLIC_KEY1", "PUBLIC_KEY2", "3.0000 IQUTXO", "1.0000 IQUTXO", {nonce}, "memo here", "{SIGNATURE}"]' -p utxo 29 | ``` 30 | 31 | ### Generating Signatures 32 | To create a signed transaction to spend UTXOs, a signature must be created by the private key of a public key with spendable outputs. We've included a front end interface to easily do that in the repository for local usage. There are also hosted solutions of the front end at: 33 | 34 | 35 | The Signature is generated with the following fields: 36 | 37 | Public key of the spender 38 | 39 | Private key of the spender 40 | 41 | Public key of the recipient 42 | 43 | Amount of UTXO to spend (denominated as uint64) 44 | 45 | Amount of UTXO to pay as fee (denominated as uint64) 46 | 47 | A nonce (we highly recommend incrementing the nonce by 1 starting from 0 for each public key) 48 | 49 | A memo/string field 50 | 51 | In the future, we will add a token ID field to add replay protection to generated signatures. 52 | 53 | ## 4. Withdrawing UTXOs out of the contract back into an EOS account 54 | 55 | To withdraw tokens from an account, issue a transfer as normal, except make the receiving public key be the NULL address, EOS1111111111111111111111111111111114T1Anm, and the memo the receiving EOS account name. 56 | 57 | The contract detects this, modifies the circulating supply, and triggers an inline action to send IQ to the EOS account specified in the memo field. 58 | 59 | ``` 60 | cleos push action utxo transfer '["{RELAYER_PUBLIC_KEY}", "{PUBLIC_KEY1}", "EOS1111111111111111111111111111111114T1Anm", "3.0000 IQUTXO", "1.0000 IQUTXO", {nonce}, "chrisaccount", "{SIGNATURE}"]' -p utxo 61 | ``` 62 | 63 | 64 | 65 | ## Running tests 66 | ``` 67 | cd js_test 68 | npm install 69 | EOSIO_CONTRACTS_ROOT=_path_to_eosio_contracts_ node test.js 70 | ``` 71 | 72 | ## Running frontend 73 | ``` 74 | cd frontend 75 | yarn install 76 | yarn start 77 | ``` 78 | -------------------------------------------------------------------------------- /bank.pay2key/relay-server/relayer.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const Joi = require('@hapi/joi'); 4 | const fetch = require('node-fetch'); 5 | const dotenv = require('dotenv'); 6 | const eosjs = require('eosjs'); 7 | const jssig = require('eosjs/dist/eosjs-jssig'); 8 | const morgan = require('morgan'); 9 | 10 | const Api = eosjs.Api; 11 | const JsonRpc = eosjs.JsonRpc; 12 | const JsSignatureProvider = jssig.JsSignatureProvider; 13 | 14 | require('dotenv').config() 15 | 16 | const app = express(); 17 | app.use(morgan('combined')); 18 | 19 | // CORS 20 | app.use(function(req, res, next) { 21 | res.header("Access-Control-Allow-Origin", "*"); 22 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 23 | next(); 24 | }); 25 | 26 | const rpc = new JsonRpc(process.env.EOS_API_BASE, { fetch }); 27 | const signatureProvider = new JsSignatureProvider([process.env.RELAYER_PRIVATE_KEY]); 28 | const eosapi = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() }); 29 | 30 | const eosSchema = Joi.object().keys({ 31 | chain_id: Joi.number().min(0).max(1000).required(), 32 | from: Joi.string().length(53).regex(/EOS.+/).required(), 33 | to: Joi.string().length(53).regex(/EOS.+/).required(), 34 | amount: Joi.string(), 35 | fee: Joi.string(), 36 | nonce: Joi.number().integer().min(0).required(), 37 | memo: Joi.string().min(0).max(163).required(), 38 | sig: Joi.string() 39 | }); 40 | 41 | const btcSchema = Joi.object().keys({ 42 | chain_id: Joi.number().min(0).max(1000).required(), 43 | from: Joi.string().min(25).max(35).required(), 44 | to: Joi.string().min(25).max(35).required(), 45 | amount: Joi.string(), 46 | fee: Joi.string(), 47 | nonce: Joi.number().integer().min(0).required(), 48 | memo: Joi.string().min(0).max(163).required(), 49 | sig: Joi.string() 50 | }); 51 | 52 | app.use(bodyParser.json()); 53 | 54 | app.post('/relay/eos', function (req, res) { 55 | const msg = req.body; 56 | const validates = Joi.validate(msg, eosSchema); 57 | if (validates.error) { 58 | const error = validates.error.details[0].message; 59 | res.status(400).send({ error: error }); 60 | console.error(error); 61 | return; 62 | } 63 | 64 | msg.relayer = process.env.RELAYER_PUBLIC_KEY; 65 | 66 | const result = eosapi.transact({ 67 | actions: [{ 68 | account: process.env.EOS_UTXO_ACCOUNT, 69 | name: 'transfer', 70 | authorization: [{ 71 | actor: process.env.RELAYER_ACCOUNT, 72 | permission: 'active', 73 | }], 74 | data: msg 75 | }] 76 | }, { 77 | blocksBehind: 3, 78 | expireSeconds: 30, 79 | }).then(response => { 80 | res.status(200).send(response); 81 | }).catch(err => { 82 | console.error(err); 83 | res.status(500).send({ error: err.message }); 84 | }); 85 | 86 | }) 87 | 88 | app.post('/relay/btc', function (req, res) { 89 | const msg = req.body; 90 | const validates = Joi.validate(msg, btcSchema); 91 | if (validates.error) { 92 | const error = validates.error.details[0].message; 93 | res.status(400).send({ error: error }); 94 | console.error(error); 95 | return; 96 | } 97 | 98 | msg.relayer = process.env.RELAYER_PUBLIC_KEY; 99 | 100 | const result = eosapi.transact({ 101 | actions: [{ 102 | account: process.env.BTC_UTXO_ACCOUNT, 103 | name: 'transfer', 104 | authorization: [{ 105 | actor: process.env.RELAYER_ACCOUNT, 106 | permission: 'active', 107 | }], 108 | data: msg 109 | }] 110 | }, { 111 | blocksBehind: 3, 112 | expireSeconds: 30, 113 | }).then(response => { 114 | res.status(200).send(response); 115 | }).catch(err => { 116 | console.error(err); 117 | res.status(500).send({ error: err.message }); 118 | }); 119 | 120 | }) 121 | 122 | app.listen(6400, (e) => { 123 | if (e) console.error(e); 124 | else console.log("Relay server listening on port 6400..."); 125 | }); 126 | -------------------------------------------------------------------------------- /tests/pay2key.test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CYAN='\033[1;36m' 4 | NC='\033[0m' 5 | 6 | assert () 7 | { 8 | 9 | if [ $1 -eq 0 ]; then 10 | FAIL_LINE=$( caller | awk '{print $1}') 11 | echo -e "Assertion failed. Line $FAIL_LINE:" 12 | head -n $FAIL_LINE $BASH_SOURCE | tail -n 1 13 | exit 99 14 | fi 15 | } 16 | 17 | PRIVKEY1="5JW2ZpYaHA96yEpDXW1arVmEezV3XPF6aD2b7BB5EyGUEapdUTL" 18 | PUBKEY1="EOS6u25uWXi52QLp1FurM8KPDJydbvxbrPM2XNrYPz7vPCQuGFCer" 19 | PRIVKEY2="5KRKuMUFswLXmeA9wzWvn6f9a9fNH36oGkVG29X2VGpbMPCJ3eC" 20 | PUBKEY2="EOS6wh7kToXbq6rt92bFVFz2mj9AcJf8NEFK3sFfYk78QTnEGAiBp" 21 | WITHDRAW_PUBKEY="EOS1111111111111111111111111111111114T1Anm" 22 | 23 | echo -e "${CYAN}-----------------------DEPLOY CONTRACT-----------------------${NC}" 24 | cleos set contract bank.pay2key ../bank.pay2key/ 25 | 26 | echo -e "${CYAN}-----------------------CREATE TOKENS-----------------------${NC}" 27 | cleos push action bank.pay2key create '["eosio.token", "4,EOS"]' -p bank.pay2key 28 | cleos push action bank.pay2key create '["everipediaiq", "3,IQ"]' -p bank.pay2key 29 | 30 | echo -e "${CYAN}-----------------------DEPOSIT TOKENS-----------------------${NC}" 31 | cleos transfer dcbtestusera bank.pay2key "100 EOS" "$PUBKEY1" 32 | assert $(bc <<< "$? == 0") 33 | cleos push action everipediaiq transfer "[\"dcbtestuserb\", \"bank.pay2key\", \"1000.000 IQ\", \"$PUBKEY2\"]" -p dcbtestuserb 34 | assert $(bc <<< "$? == 0") 35 | 36 | echo -e "${CYAN}-----------------------TRANSFER TOKENS-----------------------${NC}" 37 | NONCE1=$(cleos get table bank.pay2key 0 accounts | jq ".rows[0].last_nonce") 38 | NONCE1=$(echo "$NONCE1 + 1" | bc) 39 | MEMO1="EOS transfer" 40 | CHAIN1=0 41 | SIG1=$(node pay2key.sign.js $CHAIN1 $PUBKEY1 $PUBKEY2 10000 10 $NONCE1 "$MEMO1" $PRIVKEY1) 42 | cleos push action bank.pay2key transfer "[$CHAIN1, \"dcbtestusera\", \"$PUBKEY1\", \"$PUBKEY1\", \"$PUBKEY2\", \"1.0000 EOS\", \"0.0010 EOS\", $NONCE1, \"$MEMO1\", \"$SIG1\"]" -p dcbtestusera 43 | assert $(bc <<< "$? == 0") 44 | 45 | NONCE2=$(cleos get table bank.pay2key 1 accounts | jq ".rows[0].last_nonce") 46 | NONCE2=$(echo "$NONCE2 + 1" | bc) 47 | MEMO2="IQ transfer" 48 | CHAIN2=1 49 | SIG2=$(node pay2key.sign.js $CHAIN2 $PUBKEY2 $PUBKEY1 20300 15 $NONCE2 "$MEMO2" $PRIVKEY2) 50 | cleos push action bank.pay2key transfer "[$CHAIN2, \"dcbtestuserb\", \"$PUBKEY2\", \"$PUBKEY2\", \"$PUBKEY1\", \"20.300 IQ\", \"0.015 IQ\", $NONCE2, \"$MEMO2\", \"$SIG2\"]" -p dcbtestuserb 51 | assert $(bc <<< "$? == 0") 52 | 53 | echo -e "${CYAN}-----------------REPLAY PROTECTION (TRANSFER SHOULD FAIL)------------------${NC}" 54 | # Amount and fee are multiplied by 10 because they IQ has 3 decimal places and EOS has 4 55 | cleos push action bank.pay2key transfer "[$CHAIN2, \"dcbtestusera\", \"$PUBKEY1\", \"$PUBKEY1\", \"$PUBKEY2\", \"10.000 IQ\", \"0.010 IQ\", $NONCE1, \"$MEMO1\", \"$SIG1\"]" -p dcbtestusera 56 | assert $(bc <<< "$? == 1") 57 | 58 | echo -e "${CYAN}-----------------------WITHDRAW------------------------${NC}" 59 | EOS_BALANCE_BEFORE=$(cleos get table eosio.token dcbtestusera accounts | jq ".rows[0].balance" | tr -d '"' | awk '{print $1}') 60 | IQ_BALANCE_BEFORE=$(cleos get table everipediaiq dcbtestuserb accounts | jq ".rows[0].balance" | tr -d '"' | awk '{print $1}') 61 | 62 | NONCE3=$(echo "$NONCE1 + 1" | bc) 63 | MEMO3="dcbtestusera" 64 | SIG3=$(node pay2key.sign.js $CHAIN1 $PUBKEY1 $WITHDRAW_PUBKEY 20000 10 $NONCE3 "$MEMO3" $PRIVKEY1) 65 | cleos push action bank.pay2key transfer "[$CHAIN1, \"dcbtestusera\", \"$PUBKEY1\", \"$PUBKEY1\", \"$WITHDRAW_PUBKEY\", \"2.0000 EOS\", \"0.0010 EOS\", $NONCE3, \"$MEMO3\", \"$SIG3\"]" -p dcbtestusera 66 | assert $(bc <<< "$? == 0") 67 | 68 | NONCE4=$(echo "$NONCE2 + 1" | bc) 69 | MEMO4="dcbtestuserb:test memo" 70 | SIG4=$(node pay2key.sign.js $CHAIN2 $PUBKEY2 $WITHDRAW_PUBKEY 30000 15 $NONCE4 "$MEMO4" $PRIVKEY2) 71 | cleos push action bank.pay2key transfer "[$CHAIN2, \"dcbtestuserb\", \"$PUBKEY2\", \"$PUBKEY2\", \"$WITHDRAW_PUBKEY\", \"30.000 IQ\", \"0.015 IQ\", $NONCE4, \"$MEMO4\", \"$SIG4\"]" -p dcbtestuserb 72 | assert $(bc <<< "$? == 0") 73 | 74 | # edge case with just a colon 75 | NONCE5=$(echo "$NONCE4 + 1" | bc) 76 | MEMO5="dcbtestuserb:" 77 | SIG5=$(node pay2key.sign.js $CHAIN2 $PUBKEY2 $WITHDRAW_PUBKEY 30000 15 $NONCE5 "$MEMO5" $PRIVKEY2) 78 | cleos push action bank.pay2key transfer "[$CHAIN2, \"dcbtestuserb\", \"$PUBKEY2\", \"$PUBKEY2\", \"$WITHDRAW_PUBKEY\", \"30.000 IQ\", \"0.015 IQ\", $NONCE5, \"$MEMO5\", \"$SIG5\"]" -p dcbtestuserb 79 | assert $(bc <<< "$? == 0") 80 | 81 | EOS_BALANCE_AFTER=$(cleos get table eosio.token dcbtestusera accounts | jq ".rows[0].balance" | tr -d '"' | awk '{print $1}') 82 | IQ_BALANCE_AFTER=$(cleos get table everipediaiq dcbtestuserb accounts | jq ".rows[0].balance" | tr -d '"' | awk '{print $1}') 83 | 84 | assert $(bc <<< "$EOS_BALANCE_AFTER - $EOS_BALANCE_BEFORE == 2.0") 85 | assert $(bc <<< "$IQ_BALANCE_AFTER - $IQ_BALANCE_BEFORE == 60.0") 86 | -------------------------------------------------------------------------------- /bank.pay2key/js_test/test.js: -------------------------------------------------------------------------------- 1 | const ecc = require('eosjs-ecc'); 2 | const base58 = require('bs58'); 3 | const shell = require('shelljs'); 4 | 5 | const EOSIO_CONTRACTS_ROOT = '~/eosio.contracts/build/contracts'; 6 | 7 | function getKeys() { 8 | return Promise.all([ecc.randomKey(), ecc.randomKey(), ecc.randomKey()]); 9 | } 10 | 11 | function createKeyPair(privateKey) { 12 | return { 13 | public: ecc.privateToPublic(privateKey), 14 | private: privateKey, 15 | }; 16 | } 17 | 18 | function transferCommand(relayer, fromKeys, to, amount, fee, nonce, memo) { 19 | const version = 1; 20 | const length = 92 + memo.length; 21 | 22 | const pkeyFrom = base58.decode(fromKeys.public.substring(3)); 23 | const pkeyTo = base58.decode(to.substring(3)); 24 | const amountBuf = uint64_to_little_endian(amount * 10000); 25 | const feeBuf = uint64_to_little_endian(fee * 10000); 26 | const nonceBuf = uint64_to_little_endian(nonce); 27 | const memoBuf = Buffer.from(memo); 28 | 29 | // create raw tx 30 | const buffer = Buffer.alloc(length); 31 | buffer[0] = version; 32 | buffer[1] = length; 33 | pkeyFrom.copy(buffer, 2, 0, 33); 34 | pkeyTo.copy(buffer, 35, 0, 33); 35 | amountBuf.copy(buffer, 68, 0, 8); 36 | feeBuf.copy(buffer, 76, 0, 8); 37 | nonceBuf.copy(buffer, 84, 0, 8); 38 | memoBuf.copy(buffer, 92, 0, memoBuf.length); 39 | 40 | // hash raw tx 41 | const hashed = ecc.sha256(buffer, 'hex'); 42 | 43 | // sign transaction 44 | const sig = ecc.signHash(hashed, fromKeys.private); 45 | 46 | return `cleos push action bank.pay2key transfer '["${relayer}", "${fromKeys.public}", "${to}", "${amount}.0000 UTXO", "${fee}.0000 UTXO", ${nonce}, "${memo}", "${sig}"]' -p bank.pay2key`; 47 | } 48 | 49 | // due to JS limitaitons, this only has 48-bit precision, 50 | // but that's good enough for what we need 51 | function uint64_to_little_endian(num) { 52 | const buf = Buffer.alloc(8); 53 | buf.writeUIntLE(num, 0, 6); 54 | return buf; 55 | } 56 | 57 | async function test() { 58 | const privateKeys = await getKeys(); 59 | const utxoKeys = createKeyPair(privateKeys[0]); 60 | const firstAccountKeys = createKeyPair(privateKeys[1]); 61 | const secondAccountKeys = createKeyPair(privateKeys[2]); 62 | 63 | // wallet setup 64 | shell.exec('rm ~/eosio-wallet/default.wallet'); 65 | shell.exec('cleos wallet create --to-console'); 66 | shell.exec('cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3'); // EOS key 67 | shell.exec(`cleos wallet import --private-key ${utxoKeys.private}`); 68 | 69 | // account setup 70 | shell.exec(`cleos create account eosio bank.pay2key ${utxoKeys.public}`); 71 | shell.exec(`cleos create account eosio everipediaiq ${utxoKeys.public}`); 72 | shell.exec(`cleos create account eosio eosio.token ${utxoKeys.public}`); 73 | 74 | // bootstrap system contracts 75 | shell.exec(`cleos set contract eosio.token ${EOSIO_CONTRACTS_ROOT}/eosio.token/`) 76 | shell.exec(`cleos push action eosio.token create '["eosio", "1000.0000 EOS"]' -p eosio.token`) 77 | shell.exec(`cleos push action eosio.token issue '["eosio", "1000.0000 EOS", "memo"]' -p eosio`) 78 | 79 | // compilation and setting 80 | shell.exec('eosio-cpp -w -o ../bank.pay2key.wasm ../bank.pay2key.cpp'); 81 | shell.exec('cleos set contract bank.pay2key ..'); 82 | 83 | // create 84 | shell.exec('cleos push action bank.pay2key create \'["eosio.token", "EOS", 1]\' -p bank.pay2key'); 85 | shell.exec('cleos push action bank.pay2key create \'["everipediaiq", "IQ", 2]\' -p bank.pay2key'); 86 | shell.exec('cleos get table bank.pay2key bank.pay2key stats'); 87 | 88 | // issue 89 | shell.exec(`cleos transfer eosio bank.pay2key "1.0000 EOS" ${utxoKeys.public}`); 90 | shell.exec(`cleos transfer eosio bank.pay2key "5.0000 EOS" ${firstAccountKeys.public}`); 91 | shell.exec(`cleos transfer eosio bank.pay2key "5.0000 EOS" ${secondAccountKeys.public}`); 92 | shell.exec('cleos get table bank.pay2key bank.pay2key accounts'); 93 | 94 | // transfer, expected balances is 2, 7, 2 95 | shell.exec(transferCommand(utxoKeys.public, secondAccountKeys, firstAccountKeys.public, 3, 1, 1, "transfer from second account to first")); 96 | shell.exec(transferCommand(utxoKeys.public, firstAccountKeys, secondAccountKeys.public, 1, 0, 1, "transfer from second account to first")); 97 | shell.exec('cleos get table bank.pay2key bank.pay2key accounts'); 98 | 99 | // withdrawal, expected balances is 2, 2, 2 100 | shell.exec(`cleos set account permission bank.pay2key active '{ "threshold": 1, "keys": [{ "key": "${utxoKeys.public}", "weight": 1 }], "accounts": [{ "permission": { "actor":"bank.pay2key","permission":"eosio.code" }, "weight":1 } ] }' owner -p bank.pay2key`); 101 | shell.exec(transferCommand(utxoKeys.public, firstAccountKeys, 'EOS1111111111111111111111111111111114T1Anm', 5, 0, 2, 'eosio.token', 'bank.pay2key')); 102 | shell.exec('cleos get table bank.pay2key bank.pay2key accounts'); 103 | 104 | shell.exec('cleos get table bank.pay2key 340784338180 stats'); 105 | } 106 | 107 | test(); 108 | -------------------------------------------------------------------------------- /bank.pay2key/base58.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2014 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 9 | 10 | const int8_t b58digits_map[] = { 11 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 12 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 13 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 14 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, 15 | -1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1, 16 | 22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1, 17 | -1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46, 18 | 47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1, 19 | }; 20 | 21 | void memzero(void *const pnt, const size_t len) 22 | { 23 | // I'm pretty sure none of the commented out stuff below 24 | // is needed for WASM but I've left it there in case 25 | // - Kedar Iyer 26 | //#ifdef _WIN32 27 | // SecureZeroMemory(pnt, len); 28 | //#elif defined(HAVE_MEMSET_S) 29 | // memset_s(pnt, (rsize_t) len, 0, (rsize_t) len); 30 | //#elif defined(HAVE_EXPLICIT_BZERO) 31 | // explicit_bzero(pnt, len); 32 | //#elif defined(HAVE_EXPLICIT_MEMSET) 33 | // explicit_memset(pnt, 0, len); 34 | //#else 35 | volatile unsigned char *volatile pnt_ = 36 | (volatile unsigned char *volatile) pnt; 37 | size_t i = (size_t) 0U; 38 | 39 | while (i < len) { 40 | pnt_[i++] = 0U; 41 | } 42 | //#endif 43 | } 44 | 45 | 46 | bool b58enc(char *b58, size_t *b58sz, const uint8_t *bin, size_t binsz) 47 | { 48 | int carry; 49 | ssize_t i, j, high, zcount = 0; 50 | size_t size; 51 | 52 | while (zcount < (ssize_t)binsz && !bin[zcount]) 53 | ++zcount; 54 | 55 | size = (binsz - zcount) * 138 / 100 + 1; 56 | uint8_t buf[size]; 57 | memzero(buf, size); 58 | 59 | for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) 60 | { 61 | for (carry = bin[i], j = size - 1; (j > high) || carry; --j) 62 | { 63 | carry += 256 * buf[j]; 64 | buf[j] = carry % 58; 65 | carry /= 58; 66 | } 67 | } 68 | 69 | for (j = 0; j < (ssize_t)size && !buf[j]; ++j); 70 | 71 | if (*b58sz <= zcount + size - j) 72 | { 73 | *b58sz = zcount + size - j + 1; 74 | return false; 75 | } 76 | 77 | if (zcount) 78 | memset(b58, '1', zcount); 79 | for (i = zcount; j < (ssize_t)size; ++i, ++j) 80 | b58[i] = b58digits_ordered[buf[j]]; 81 | b58[i] = '\0'; 82 | *b58sz = i + 1; 83 | 84 | return true; 85 | } 86 | 87 | bool b58tobin(void *bin, size_t *binszp, const char *b58) 88 | { 89 | size_t binsz = *binszp; 90 | 91 | if (binsz == 0) { 92 | return false; 93 | } 94 | 95 | const unsigned char *b58u = (const unsigned char*)b58; 96 | unsigned char *binu = (unsigned char *)bin; 97 | size_t outisz = (binsz + 3) / 4; 98 | uint32_t outi[outisz]; 99 | uint64_t t; 100 | uint32_t c; 101 | size_t i, j; 102 | uint8_t bytesleft = binsz % 4; 103 | uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; 104 | unsigned zerocount = 0; 105 | size_t b58sz; 106 | 107 | b58sz = strlen(b58); 108 | 109 | memzero(outi, sizeof(outi)); 110 | 111 | // Leading zeros, just count 112 | for (i = 0; i < b58sz && b58u[i] == '1'; ++i) 113 | ++zerocount; 114 | 115 | for ( ; i < b58sz; ++i) 116 | { 117 | if (b58u[i] & 0x80) 118 | // High-bit set on invalid digit 119 | return false; 120 | if (b58digits_map[b58u[i]] == -1) 121 | // Invalid base58 digit 122 | return false; 123 | c = (unsigned)b58digits_map[b58u[i]]; 124 | for (j = outisz; j--; ) 125 | { 126 | t = ((uint64_t)outi[j]) * 58 + c; 127 | c = (t & 0x3f00000000) >> 32; 128 | outi[j] = t & 0xffffffff; 129 | } 130 | if (c) 131 | // Output number too big (carry to the next int32) 132 | return false; 133 | if (outi[0] & zeromask) 134 | // Output number too big (last int32 filled too far) 135 | return false; 136 | } 137 | 138 | j = 0; 139 | switch (bytesleft) { 140 | case 3: 141 | *(binu++) = (outi[0] & 0xff0000) >> 16; 142 | //-fallthrough 143 | case 2: 144 | *(binu++) = (outi[0] & 0xff00) >> 8; 145 | //-fallthrough 146 | case 1: 147 | *(binu++) = (outi[0] & 0xff); 148 | ++j; 149 | //-fallthrough 150 | default: 151 | break; 152 | } 153 | 154 | for (; j < outisz; ++j) 155 | { 156 | *(binu++) = (outi[j] >> 0x18) & 0xff; 157 | *(binu++) = (outi[j] >> 0x10) & 0xff; 158 | *(binu++) = (outi[j] >> 8) & 0xff; 159 | *(binu++) = (outi[j] >> 0) & 0xff; 160 | } 161 | 162 | // Count canonical base58 byte count 163 | binu = (unsigned char *)bin; 164 | for (i = 0; i < binsz; ++i) 165 | { 166 | if (binu[i]) { 167 | if (zerocount > i) { 168 | /* result too large */ 169 | return false; 170 | } 171 | break; 172 | } 173 | --*binszp; 174 | } 175 | *binszp += zerocount; 176 | 177 | return true; 178 | } 179 | -------------------------------------------------------------------------------- /frax.reserve/frax.reserve.cpp: -------------------------------------------------------------------------------- 1 | #include "frax.reserve.hpp" 2 | 3 | [[eosio::action]] 4 | void fraxreserve::addtoken(name contract, symbol ticker) { 5 | require_auth( _self ); 6 | 7 | check(ticker.is_valid(), "invalid symbol name"); 8 | 9 | stats statstable(_self, _self.value); 10 | auto contract_sym_index = statstable.get_index(); 11 | uint128_t merged = merge_contract_symbol(contract, ticker); 12 | auto existing = contract_sym_index.find(merged); 13 | check(existing == contract_sym_index.end(), "Token is already registered"); 14 | check(statstable.find(ticker.raw()) == statstable.end(), "Another token with that ticker already exists"); 15 | 16 | statstable.emplace(_self, [&](auto& s) { 17 | s.contract = contract; 18 | s.supply = asset(0, ticker); 19 | }); 20 | } 21 | 22 | void fraxreserve::deposit( name from, name to, asset quantity, string memo ) { 23 | if (from == _self) return; // sending tokens, ignore 24 | 25 | auto symbol = quantity.symbol; 26 | check(symbol.is_valid(), "invalid symbol name"); 27 | check(to == _self, "stop trying to hack the contract"); 28 | 29 | // make sure contract and symbol are accepted by contract 30 | stats statstable(_self, _self.value); 31 | auto contract_sym_index = statstable.get_index(); 32 | uint128_t merged = merge_contract_symbol(get_first_receiver(), symbol); 33 | auto existing = contract_sym_index.find(merged); 34 | check(existing != contract_sym_index.end(), "Token is not yet supported"); 35 | 36 | // validate arguments 37 | check(quantity.is_valid(), "invalid quantity"); 38 | check(quantity.amount < 1e10, "quantity is suspiciously high. send a smaller amount"); 39 | check(quantity.amount > 0, "must deposit positive quantity"); 40 | check(memo.size() < 256, "memo must be less than 256 bytes"); 41 | 42 | // create/update entry in table 43 | accounts deptbl( _self, from.value ); 44 | auto account_it = deptbl.find(symbol.raw()); 45 | if (account_it == deptbl.end()) { 46 | deptbl.emplace( _self, [&](auto& a) { 47 | a.balance = quantity; 48 | }); 49 | } 50 | else { 51 | deptbl.modify( account_it, _self, [&](auto& a) { 52 | a.balance += quantity; 53 | }); 54 | } 55 | 56 | } 57 | 58 | [[eosio::action]] 59 | void fraxreserve::buyfrax(name buyer, asset frax) { 60 | require_auth(buyer); 61 | 62 | check(frax.amount > 0, "Must buy a positive amount"); 63 | check(frax.symbol == FRAX_SYMBOL, "Can only buy FRAX"); 64 | 65 | sysparams paramstbl( _self, _self.value); 66 | check(paramstbl.begin() != paramstbl.end(), "Reserve params must be initialized first"); 67 | auto param_it = paramstbl.begin(); 68 | 69 | stats statstable(_self, _self.value); 70 | auto fxs_stats = statstable.find(FXS_SYMBOL.raw()); 71 | auto usdt_stats = statstable.find(USDT_SYMBOL.raw()); 72 | check(fxs_stats != statstable.end(), "Must addtoken FXS first"); 73 | check(usdt_stats != statstable.end(), "Must addtoken USDT first"); 74 | 75 | asset needed_usdt = param_it->target_usdt - usdt_stats->supply; 76 | asset needed_fxs = param_it->target_fxs - fxs_stats->supply; 77 | uint64_t needed_fxs_value = needed_fxs.amount * param_it->fxs_price / 1e4; 78 | uint64_t total_needed_value = needed_usdt.amount + needed_fxs_value; 79 | 80 | asset sell_usdt = asset(frax.amount * needed_usdt.amount / total_needed_value, USDT_SYMBOL); 81 | asset sell_fxs = asset(frax.amount * needed_fxs_value / total_needed_value, FXS_SYMBOL); 82 | check(sell_usdt <= needed_usdt, "Attempting to buy too much FRAX"); 83 | check(sell_fxs <= needed_fxs, "Attempting to buy too much FRAX"); 84 | 85 | // Update accounts and stats 86 | accounts deptbl( _self, buyer.value ); 87 | if (sell_usdt.amount > 0) { 88 | auto usdt_account = deptbl.find(USDT_SYMBOL.raw()); 89 | check(usdt_account != deptbl.end(), "No USDT balance for this user"); 90 | check(usdt_account->balance >= sell_usdt, "Not enough USDT balance to buy FRAX"); 91 | deptbl.modify( usdt_account, _self, [&](auto& a) { 92 | a.balance -= sell_usdt; 93 | }); 94 | statstable.modify( usdt_stats, same_payer, [&](auto& usdt) { 95 | usdt.supply += sell_usdt; 96 | }); 97 | } 98 | if (sell_fxs.amount > 0) { 99 | auto fxs_account = deptbl.find(FXS_SYMBOL.raw()); 100 | check(fxs_account != deptbl.end(), "No FXS balance for this user"); 101 | check(fxs_account->balance >= sell_fxs, "Not enough FXS balance to buy FRAX"); 102 | deptbl.modify( fxs_account, _self, [&](auto& a) { 103 | a.balance -= sell_fxs; 104 | }); 105 | statstable.modify( fxs_stats, same_payer, [&](auto& fxs) { 106 | fxs.supply += sell_fxs; 107 | }); 108 | } 109 | 110 | // Issue FRAX 111 | action( 112 | permission_level { _self, name("active") }, 113 | name("fraxtokenfxs"), name("issue"), 114 | std::make_tuple( buyer, frax, std::string("issue FRAX") ) 115 | ).send(); 116 | 117 | } 118 | 119 | [[eosio::action]] 120 | void fraxreserve::settarget(asset target_usdt, asset target_fxs, uint64_t fxs_price) { 121 | require_auth( _self ); 122 | 123 | check(target_usdt.symbol == USDT_SYMBOL, "Symbol mismatch for target_usdt"); 124 | check(target_fxs.symbol == FXS_SYMBOL, "Symbol mismatch for target_usdt"); 125 | check(fxs_price > 0, "fxs_price must be postive"); 126 | 127 | sysparams paramstbl( _self, _self.value); 128 | if (paramstbl.begin() == paramstbl.end()) { 129 | paramstbl.emplace( _self, [&](auto& p) { 130 | p.target_usdt = target_usdt; 131 | p.target_fxs = target_fxs; 132 | p.fxs_price = fxs_price; 133 | }); 134 | } 135 | else { 136 | paramstbl.modify( paramstbl.begin(), _self, [&](auto& p) { 137 | p.target_usdt = target_usdt; 138 | p.target_fxs = target_fxs; 139 | }); 140 | } 141 | 142 | } 143 | 144 | extern "C" void apply(uint64_t receiver, uint64_t code, uint64_t action) 145 | { 146 | auto _self = receiver; 147 | if (code != _self && action == name("transfer").value) 148 | { 149 | eosio::execute_action( 150 | eosio::name(receiver), eosio::name(code), &fraxreserve::deposit 151 | ); 152 | } 153 | else if (code == _self) 154 | { 155 | switch (action) { 156 | EOSIO_DISPATCH_HELPER( fraxreserve, (addtoken)(buyfrax)(settarget) ) 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /tests/fraxloans_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "contracts.hpp" 4 | #include "token_test_api.hpp" 5 | #include "fraxloans_api.hpp" 6 | 7 | using namespace eosio::testing; 8 | using namespace eosio; 9 | using namespace eosio::chain; 10 | using namespace fc; 11 | using namespace std; 12 | 13 | using mvo = fc::mutable_variant_object; 14 | 15 | #define SUCCESS(call) BOOST_REQUIRE_EQUAL(success(), call) 16 | #define ERROR(msg, call) BOOST_REQUIRE_EQUAL(wasm_assert_msg(msg), call) 17 | 18 | class fraxloans_tester: public tester 19 | { 20 | protected: 21 | token_test_api fraxtokens; 22 | token_test_api tether; 23 | token_test_api eos; 24 | fraxloans_api fraxloans; 25 | public: 26 | fraxloans_tester(): 27 | fraxtokens(N(frax.token), this), 28 | tether(N(tethertether), this), 29 | eos(N(eosio.token), this), 30 | fraxloans(N(frax.loans), this) 31 | { 32 | create_accounts({ N(alice), N(bob), N(carol) }); 33 | produce_blocks(2); 34 | init_tokens(); 35 | } 36 | 37 | private: 38 | void init_tokens() 39 | { 40 | SUCCESS(eos.push_action(eos.contract, eos.contract, N(create), mvo() 41 | ("issuer", eos.contract) 42 | ("maximum_supply", asset::from_string("10000000000.0000 EOS")) 43 | )); 44 | 45 | SUCCESS(eos.push_action(eos.contract, eos.contract, N(issue), mvo() 46 | ("to", eos.contract) 47 | ("quantity", asset::from_string("100000.0000 EOS")) 48 | ("memo", "") 49 | )); 50 | 51 | SUCCESS(tether.push_action(tether.contract, tether.contract, N(create), mvo() 52 | ("issuer", tether.contract) 53 | ("maximum_supply", asset::from_string("10000000000.0000 USDT")) 54 | )); 55 | 56 | SUCCESS(tether.push_action(tether.contract, tether.contract, N(issue), mvo() 57 | ("to", tether.contract) 58 | ("quantity", asset::from_string("100000.0000 USDT")) 59 | ("memo", "") 60 | )); 61 | 62 | SUCCESS(fraxtokens.push_action(fraxtokens.contract, fraxtokens.contract, N(create), mvo() 63 | ("issuer", fraxtokens.contract) 64 | ("maximum_supply", asset::from_string("100000.0000 FRAX")) 65 | )); 66 | 67 | SUCCESS(fraxtokens.push_action(fraxtokens.contract, fraxtokens.contract, N(create), mvo() 68 | ("issuer", fraxtokens.contract) 69 | ("maximum_supply", asset::from_string("100000.0000 FXS")) 70 | )); 71 | 72 | SUCCESS(fraxtokens.push_action(fraxtokens.contract, fraxtokens.contract, N(issue), mvo() 73 | ("to", fraxtokens.contract) 74 | ("quantity", asset::from_string("100000.0000 FRAX")) 75 | ("memo", "") 76 | )); 77 | 78 | SUCCESS(fraxtokens.push_action(fraxtokens.contract, fraxtokens.contract, N(issue), mvo() 79 | ("to", fraxtokens.contract) 80 | ("quantity", asset::from_string("100000.0000 FXS")) 81 | ("memo", "") 82 | )); 83 | 84 | SUCCESS(fraxtokens.transfer(fraxtokens.contract, N(alice), asset::from_string("1000.0000 FRAX"))); 85 | SUCCESS(fraxtokens.transfer(fraxtokens.contract, N(bob), asset::from_string("1000.0000 FRAX"))); 86 | SUCCESS(fraxtokens.transfer(fraxtokens.contract, N(carol), asset::from_string("1000.0000 FRAX"))); 87 | SUCCESS(fraxtokens.transfer(fraxtokens.contract, N(alice), asset::from_string("1000.0000 FXS"))); 88 | SUCCESS(fraxtokens.transfer(fraxtokens.contract, N(bob), asset::from_string("1000.0000 FXS"))); 89 | SUCCESS(fraxtokens.transfer(fraxtokens.contract, N(carol), asset::from_string("1000.0000 FXS"))); 90 | SUCCESS(eos.transfer(eos.contract, N(alice), asset::from_string("1000.0000 EOS"))); 91 | SUCCESS(eos.transfer(eos.contract, N(bob), asset::from_string("1000.0000 EOS"))); 92 | SUCCESS(eos.transfer(eos.contract, N(carol), asset::from_string("1000.0000 EOS"))); 93 | SUCCESS(tether.transfer(tether.contract, N(alice), asset::from_string("10000.0000 USDT"))); 94 | SUCCESS(tether.transfer(tether.contract, N(bob), asset::from_string("10000.0000 USDT"))); 95 | SUCCESS(tether.transfer(tether.contract, N(carol), asset::from_string("10000.0000 USDT"))); 96 | 97 | // enable tokens in frax loans module 98 | SUCCESS(fraxloans.addtoken(fraxtokens.contract, "4,FRAX")); 99 | SUCCESS(fraxloans.addtoken(fraxtokens.contract, "4,FXS")); 100 | SUCCESS(fraxloans.addtoken(tether.contract, "4,USDT")); 101 | SUCCESS(fraxloans.addtoken(eos.contract, "4,EOS")); 102 | 103 | } 104 | }; 105 | 106 | BOOST_AUTO_TEST_SUITE(fraxloans_tests) 107 | 108 | BOOST_FIXTURE_TEST_CASE(fraxloans_full, fraxloans_tester) try { 109 | // deposit for supply 110 | SUCCESS(tether.transfer(N(carol), fraxloans.contract, asset::from_string("1000.0000 USDT"))); 111 | SUCCESS(eos.transfer(N(carol), fraxloans.contract, asset::from_string("1000.0000 EOS"))); 112 | SUCCESS(fraxtokens.transfer(N(alice), fraxloans.contract, asset::from_string("1000.0000 FRAX"))); 113 | SUCCESS(fraxtokens.transfer(N(bob), fraxloans.contract, asset::from_string("1000.0000 FXS"))); 114 | 115 | auto tether_stats = fraxloans.get_tokenstats("4,USDT"); 116 | auto eos_stats = fraxloans.get_tokenstats("4,EOS"); 117 | auto frax_stats = fraxloans.get_tokenstats("4,FRAX"); 118 | auto fxs_stats = fraxloans.get_tokenstats("4,FXS"); 119 | auto alice_frax = fraxloans.get_account(N(alice), "4,FRAX"); 120 | auto carol_tether = fraxloans.get_account(N(carol), "4,USDT"); 121 | auto carol_eos = fraxloans.get_account(N(carol), "4,EOS"); 122 | auto bob_fxs = fraxloans.get_account(N(bob), "4,FXS"); 123 | BOOST_REQUIRE_EQUAL(tether_stats["available"], "1000.0000 USDT"); 124 | BOOST_REQUIRE_EQUAL(eos_stats["available"], "1000.0000 EOS"); 125 | BOOST_REQUIRE_EQUAL(fxs_stats["available"], "1000.0000 FXS"); 126 | BOOST_REQUIRE_EQUAL(frax_stats["available"], "1000.0000 FRAX"); 127 | BOOST_REQUIRE_EQUAL(alice_frax["balance"], "1000.0000 FRAX"); 128 | BOOST_REQUIRE_EQUAL(carol_tether["balance"], "1000.0000 USDT"); 129 | BOOST_REQUIRE_EQUAL(carol_eos["balance"], "1000.0000 EOS"); 130 | BOOST_REQUIRE_EQUAL(bob_fxs["balance"], "1000.0000 FXS"); 131 | 132 | // deposit for collateral 133 | SUCCESS(eos.transfer(N(alice), fraxloans.contract, asset::from_string("1000.0000 EOS"))); 134 | SUCCESS(tether.transfer(N(bob), fraxloans.contract, asset::from_string("2000.0000 USDT"))); 135 | 136 | // set token prices 137 | SUCCESS(fraxloans.setprice(asset::from_string("1.000 FRAX"))); 138 | SUCCESS(fraxloans.setprice(asset::from_string("3.500 EOS"))); 139 | SUCCESS(fraxloans.setprice(asset::from_string("1.000 FXS"))); 140 | SUCCESS(fraxloans.setprice(asset::from_string("1.000 USDT"))); 141 | 142 | // borrow 143 | SUCCESS(fraxloans.borrow(N(alice), asset::from_string("1000.0000 USDT"))); 144 | SUCCESS(fraxloans.borrow(N(bob), asset::from_string("300.0000 EOS"))); 145 | 146 | auto alice_usdt = fraxloans.get_account(N(alice), "4,USDT"); 147 | auto bob_eos = fraxloans.get_account(N(bob), "4,EOS"); 148 | BOOST_REQUIRE_EQUAL(alice_usdt["balance"], "1000.0000 USDT"); 149 | BOOST_REQUIRE_EQUAL(alice_usdt["borrowing"], "1000.0000 USDT"); 150 | BOOST_REQUIRE_EQUAL(bob_eos["balance"], "300.0000 EOS"); 151 | BOOST_REQUIRE_EQUAL(bob_eos["borrowing"], "300.0000 EOS"); 152 | 153 | // accrue interest 154 | produce_blocks(1000); 155 | } 156 | FC_LOG_AND_RETHROW() 157 | 158 | BOOST_AUTO_TEST_SUITE_END() 159 | -------------------------------------------------------------------------------- /bank.pay2key/frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './App.css'; 3 | 4 | const ecc = require('eosjs-ecc'); 5 | const base58 = require('bs58'); 6 | 7 | class App extends Component { 8 | constructor(props) { 9 | super(props); 10 | this.state = { 11 | from: '', 12 | fromPrivateKey: '', 13 | to: '', 14 | amount: 0, 15 | fee: 1, 16 | nonce: 1, 17 | memo: '', 18 | sig: '', 19 | }; 20 | } 21 | 22 | targetValue = (target) => { 23 | switch(target.type) { 24 | case "number": 25 | return target.valueAsNumber; 26 | case "text": 27 | return target.value; 28 | default: 29 | throw new Error("Unexpected target type"); 30 | } 31 | } 32 | 33 | handleChange = (event) => { 34 | this.setState({ [event.target.name]: this.targetValue(event.target) }); 35 | } 36 | 37 | handleSubmit = (event) => { 38 | event.preventDefault(); 39 | const sig = this.transactionSignature(this.state.from, 40 | this.state.fromPrivateKey, 41 | this.state.to, 42 | this.state.amount, 43 | this.state.fee, 44 | this.state.nonce, 45 | this.state.memo); 46 | this.setState({ sig: sig }); 47 | console.log(sig); 48 | this.apiRequest(sig); 49 | } 50 | 51 | // due to JS limitaitons, this only has 48-bit precision, 52 | // but that's good enough for what we need 53 | uint64_to_little_endian(num) { 54 | const buf = Buffer.alloc(8); 55 | buf.writeUIntLE(num, 0, 6); 56 | return buf; 57 | } 58 | 59 | transactionSignature(fromPublicKey, fromPrivateKey, toPublicKey, amount, fee, nonce, memo) { 60 | const version = 1; 61 | const length = 92 + memo.length; 62 | 63 | const pkeyFrom = base58.decode(fromPublicKey.substring(3)); 64 | const pkeyTo = base58.decode(toPublicKey.substring(3)); 65 | const amountBuf = this.uint64_to_little_endian(amount); 66 | const feeBuf = this.uint64_to_little_endian(fee); 67 | const nonceBuf = this.uint64_to_little_endian(nonce); 68 | const memoBuf = Buffer.from(memo); 69 | 70 | // create raw tx 71 | const buffer = Buffer.alloc(length); 72 | buffer[0] = version; 73 | buffer[1] = length; 74 | pkeyFrom.copy(buffer, 2, 0, 33); 75 | pkeyTo.copy(buffer, 35, 0, 33); 76 | amountBuf.copy(buffer, 68, 0, 8); 77 | feeBuf.copy(buffer, 76, 0, 8); 78 | nonceBuf.copy(buffer, 84, 0, 8); 79 | memoBuf.copy(buffer, 92, 0, memoBuf.length); 80 | 81 | // hash raw tx 82 | const hashed = ecc.sha256(buffer, 'hex'); 83 | 84 | return ecc.signHash(hashed, fromPrivateKey); 85 | } 86 | 87 | async apiRequest(signature) { 88 | this.setState({ error: null }); 89 | const RELAY_ENDPOINT = "https://relayer.utxo.libertyblock.io/relay"; 90 | const relay_response = await fetch(RELAY_ENDPOINT, { 91 | method: 'POST', 92 | headers: { 93 | 'Accept': 'application/json', 94 | 'Content-Type': 'application/json', 95 | }, 96 | body: JSON.stringify({ 97 | from: this.state.from, 98 | to: this.state.to, 99 | amount: (this.state.amount / 1000).toFixed(3) + " IQUTXO", 100 | fee: (this.state.fee / 1000).toFixed(3) + " IQUTXO", 101 | nonce: this.state.nonce, 102 | memo: this.state.memo, 103 | sig: signature 104 | }) 105 | }) 106 | .then(response => response.json()) 107 | 108 | console.log(relay_response); 109 | if (relay_response.error) 110 | this.setState({ error: relay_response.error }); 111 | else 112 | this.setState({ txid: relay_response.transaction_id }); 113 | } 114 | 115 | isSubmitDisabled() { 116 | return this.state.from === '' || 117 | this.state.fromPrivateKey === '' || 118 | this.state.to === '' || 119 | isNaN(this.state.amount) || 120 | isNaN(this.state.fee) || 121 | isNaN(this.state.nonce); 122 | } 123 | 124 | render() { 125 | const { txid, error } = this.state; 126 | 127 | return ( 128 |
129 |

IQ Pay-to-key

130 |
131 | 140 | 149 | 158 | 166 | 174 | 182 | 190 | 191 |
192 | 193 | {error ?
{error}
: null } 194 | {txid ? 195 |
196 | You transfer was successful. View it here 197 |
: null 198 | } 199 |
200 | ); 201 | } 202 | } 203 | 204 | export default App; 205 | -------------------------------------------------------------------------------- /bank.shares/bank.shares.cpp: -------------------------------------------------------------------------------- 1 | #include "bank.shares.hpp" 2 | 3 | 4 | // Start a reverse Dutch auction exchange BANK (or SYS) [SYS_TOKEN_NAME] for bank.token currency 5 | [[eosio::action]] 6 | void bankshares::startauction(asset quantity, asset askstart, asset askfloor, string memo, time_point end_time) { 7 | // Check authorization 8 | require_auth( _self ); 9 | 10 | // Validate issue quantity 11 | eosio_assert( quantity.symbol.is_valid(), "Invalid symbol name for quantity" ); 12 | eosio_assert( quantity.is_valid(), "Invalid quantity"); 13 | eosio_assert( quantity.symbol.name == SYS_TOKEN_NAME, "Invalid system token name in quantity"); 14 | eosio_assert( quantity.amount.is_valid(), "Invalid quantity quantity" ); 15 | eosio_assert( quantity.amount > 0, "Issue quantity must be positive"); 16 | 17 | // Validate askstart quantity 18 | eosio_assert( askstart.symbol.is_valid(), "Invalid symbol name for askstart" ); 19 | eosio_assert( askstart.is_valid(), "Invalid askstart"); 20 | eosio_assert( askstart.amount.is_valid(), "Invalid askstart quantity" ); 21 | eosio_assert( askstart.amount > 0, "askstart quantity must be positive"); 22 | 23 | // Validate askfloor quantity 24 | eosio_assert( askfloor.symbol.is_valid(), "Invalid symbol name for askfloor" ); 25 | eosio_assert( askfloor.is_valid(), "Invalid askfloor"); 26 | eosio_assert( askfloor.amount.is_valid(), "Invalid askfloor quantity" ); 27 | eosio_assert( askfloor.amount > 0, "askfloor quantity must be positive"); 28 | 29 | // Make sure the ask floor and the ask start symbols are the same 30 | eosio_assert( askstart.symbol.name == askfloor.symbol.name, "askfloor and askstart symbol name mismatch"); 31 | 32 | // Validate memo 33 | eosio_assert(memo.size() <= 163, "memo has more than 164 bytes"); 34 | 35 | // Validate the exchange currency 36 | eosio_assert(exchcurrsymb.is_valid(), "Invalid symbol name for exchange currency"); 37 | 38 | // Validate that the accepted exchange currency exists. Assuming it has a statstable too 39 | // Make sure the currency actually exists 40 | banktoken::stats stats_tbl("bank.token"_n, "bank.token"_n.value); 41 | auto stats_it = stats_tbl.find(askfloor.symbol.raw()); 42 | eosio_assert(stats_it != statstable.end(), "Provided bank.token currency does not exist"); 43 | 44 | // Validate the time 45 | eosio_assert( end_time > now(), "Ending time of the auction must be in the future" ); 46 | 47 | // Issue more SYS_TOKEN_NAME by calling the system contract 48 | action issuance = action( 49 | permission_level{_self,"active"_n}, 50 | "eosio.token"_n, 51 | "issue"_n, 52 | {"bank.shares"_n, quantity, memo } 53 | ); 54 | issuance.send(); 55 | 56 | // Create the auction 57 | auctions auctions_tbl(_self, _self.value); 58 | auctions_tbl.emplace(_self, [&](auto& auct) { 59 | auct.id = auctions_tbl.available_primary_key(); 60 | auct.issue = quantity; 61 | auct.iss_remain = quantity; 62 | auct.current_ask = askstart; 63 | auct.ask_floor = askfloor; 64 | auct.start_time = now(); 65 | auct.end_time = end_time; 66 | }); 67 | } 68 | 69 | // Sell currency for SYS_TOKEN_NAME shares 70 | [[eosio::action]] 71 | void bankshares::buyshares(uint64_t auctionid, name buyer, asset buyamount, asset maxbid) { 72 | // Update the ask and also check to make sure the auction exists and is valid. 73 | // Returns the iterator to the 74 | auto auctionsPack = update_ask_local(auctionid); 75 | 76 | // Make sure the buy amount is in SYS_TOKEN_NAME tokens 77 | eosio_assert( buyamount.symbol.name == SYS_TOKEN_NAME, "Invalid system token name in buyamount"); 78 | 79 | // Make sure the bid is in the correct currency that the auction is asking for 80 | eosio_assert( auctionsPack._it->current_ask.symbol.name == maxbid.symbol.name, "Invalid currency in the maxbid"); 81 | 82 | // Price checks 83 | eosio_assert( maxbid.amount >= auctionsPack._it->current_ask.amount , "Your maximum bid is too low" ); 84 | 85 | // Make sure there is suffient SYS_TOKEN_NAME left to sell. 86 | eosio_assert( auctionsPack._it->iss_remain >= buyamount.amount, "Not enough SYS_TOKEN_NAME left to buy"); 87 | 88 | // Make sure the seller has enough currency 89 | banktoken::accounts accounts_tbl(buyer, buyer.value); 90 | auto accounts_it = accounts_tbl.find(sellamount.symbol.raw()); 91 | eosio_assert(accounts_it != accounts_tbl.end(), "No balance found for the provided currency in bank.token"); 92 | uint64_t currency_amount = (buyamount.amount * auctionsPack._it->current_ask.amount) 93 | asset currencyPack = asset(int64_t(currency_amount), maxbid.symbol); 94 | eosio_assert(accounts_it->balance.amount >= currency_amount), "You don't have enough currency to make a complete purchase"); 95 | 96 | // Have the buyer send the tokens to the the bank.shares contract 97 | action givecurrency = action( 98 | permission_level{buyer,"active"_n}, 99 | "bank.token"_n, 100 | "transfer"_n, 101 | {buyer, "bank.shares"_n, currencyPack, "memo" } 102 | ); 103 | givecurrency.send(); 104 | 105 | // Give the buyer the SYS_TOKEN_NAME 106 | action givesys = action( 107 | permission_level{_self,"active"_n}, 108 | "eosio.token"_n, 109 | "transfer"_n, 110 | {_self, buyer, buyamount, "memo" } 111 | ); 112 | givesys.send(); 113 | 114 | // Update the auction 115 | auctionsPack._tbl.modify( auctionsPack._it, _self, [&]( auto& auct ) { 116 | auct.current_ask = asset(int64_t(auctionsPack._it->iss_remain.amount - currencyPack.amount), buyamount.symbol); 117 | }); 118 | 119 | } 120 | 121 | // Update the ask (blockchain accessible) 122 | [[eosio::action]] 123 | void bankshares::updateask(uint64_t auctionid) { 124 | update_ask_local(auctionid); 125 | } 126 | 127 | // Update the ask (internal function). Returns the auction iterator and table as a struct 128 | bankshares::AuctionPack bankshares::update_ask_local(uint64_t auctionid){ 129 | // Fetch the auction and store it in the struct 130 | auctions auctions_tbl(_self, _self.value); 131 | auto auctions_it = auctions_tbl.find( auctionid ); 132 | bankshares::AuctionPack aPack = {auctions_it, auctions_tbl}; 133 | 134 | // Validation 135 | eosio_assert( auctions_it != auctions_tbl.end(), "Auction not found" ); 136 | eosio_assert( auctions_it->end_time > now(), "Auction has ended" ); 137 | eosio_assert( auctions_it->iss_remain.amount > 0, "Issue has sold out"); 138 | 139 | // Calculate the new asking price for 1 SYS_TOKEN_NAME 140 | // Linear algorithm for now [fraction of time left x (current_ask - ask_floor) + ask_floor] 141 | float fraction_time_left = ((now() - auctions_it->start_time) / (auctions_it->end_time - auctions_it->start_time)) 142 | int64_t newask_amt = (fraction_time_left * (auctions_it->current_ask - auctions_it->ask_floor) + auctions_it->ask_floor) 143 | asset newask = asset(newask_amt, auctions_it->get_symbol()); 144 | 145 | // Make sure the new ask is bounded by the current ask and the floor 146 | eosio_assert( newask.amount >= auctions_it->ask_floor.amount, "Calculated new ask is below floor ask" ); 147 | eosio_assert( newask.amount < auctions_it->current_ask.amount, "Calculated new ask is above current ask" ); 148 | 149 | // Update the ask 150 | auctions_tbl.modify( auctions_it, _self, [&]( auto& auct ) { 151 | auct.current_ask = newask; 152 | }); 153 | 154 | return aPack; 155 | } 156 | 157 | EOSIO_DISPATCH(bankshares, (buyshares)(startauction)(updateask)) -------------------------------------------------------------------------------- /tests/fraxreserve.test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CYAN='\033[1;36m' 4 | NC='\033[0m' 5 | 6 | assert () 7 | { 8 | 9 | if [ $1 -eq 0 ]; then 10 | FAIL_LINE=$( caller | awk '{print $1}') 11 | echo -e "Assertion failed. Line $FAIL_LINE:" 12 | head -n $FAIL_LINE $BASH_SOURCE | tail -n 1 13 | exit 99 14 | fi 15 | } 16 | 17 | echo -e "${CYAN}-----------------------DEPLOY CONTRACT-----------------------${NC}" 18 | cleos set contract frax.reserve ../frax.reserve/ 19 | 20 | echo -e "${CYAN}-----------------------ADD TOKENS-----------------------${NC}" 21 | cleos push action frax.reserve addtoken '["tethertether", "4,USDT"]' -p frax.reserve 22 | cleos push action frax.reserve addtoken '["fraxtokenfxs", "4,FXS"]' -p frax.reserve 23 | 24 | echo -e "${CYAN}-----------------------DEPOSIT TOKENS-----------------------${NC}" 25 | OLD_BALANCE1=$(cleos get table frax.reserve dcbtestusera accounts | jq '.rows[]' | grep USDT | tr -d '"' | awk '{ print $2 }') 26 | OLD_BALANCE2=$(cleos get table frax.reserve dcbtestuserb accounts | jq '.rows[]' | grep USDT | tr -d '"' | awk '{ print $2 }') 27 | OLD_BALANCE3=$(cleos get table frax.reserve dcbtestusera accounts | jq '.rows[]' | grep FXS | tr -d '"' | awk '{ print $2 }') 28 | OLD_BALANCE4=$(cleos get table frax.reserve dcbtestuserb accounts | jq '.rows[]' | grep FXS | tr -d '"' | awk '{ print $2 }') 29 | 30 | cleos push action tethertether transfer '["dcbtestusera", "frax.reserve", "2000.0000 USDT", "deposit USDT"]' -p dcbtestusera 31 | assert $(bc <<< "$? == 0") 32 | cleos push action tethertether transfer '["dcbtestuserb", "frax.reserve", "3000.0000 USDT", "deposit USDT"]' -p dcbtestuserb 33 | assert $(bc <<< "$? == 0") 34 | cleos push action fraxtokenfxs transfer '["dcbtestusera", "frax.reserve", "1000.0000 FXS", "deposit FXS"]' -p dcbtestusera 35 | assert $(bc <<< "$? == 0") 36 | cleos push action fraxtokenfxs transfer '["dcbtestuserb", "frax.reserve", "1000.0000 FXS", "deposit FXS"]' -p dcbtestuserb 37 | assert $(bc <<< "$? == 0") 38 | 39 | NEW_BALANCE1=$(cleos get table frax.reserve dcbtestusera accounts | jq '.rows[]' | grep USDT | tr -d '"' | awk '{ print $2 }') 40 | NEW_BALANCE2=$(cleos get table frax.reserve dcbtestuserb accounts | jq '.rows[]' | grep USDT | tr -d '"' | awk '{ print $2 }') 41 | NEW_BALANCE3=$(cleos get table frax.reserve dcbtestusera accounts | jq '.rows[]' | grep FXS | tr -d '"' | awk '{ print $2 }') 42 | NEW_BALANCE4=$(cleos get table frax.reserve dcbtestuserb accounts | jq '.rows[]' | grep FXS | tr -d '"' | awk '{ print $2 }') 43 | 44 | assert $(bc <<< "$NEW_BALANCE1 - $OLD_BALANCE1 == 2000") 45 | assert $(bc <<< "$NEW_BALANCE2 - $OLD_BALANCE2 == 3000") 46 | assert $(bc <<< "$NEW_BALANCE3 - $OLD_BALANCE3 == 1000") 47 | assert $(bc <<< "$NEW_BALANCE4 - $OLD_BALANCE4 == 1000") 48 | 49 | echo -e "${CYAN}-----------------------DEPOSIT UNSUPPORTED TOKENS-----------------------${NC}" 50 | cleos transfer dcbtestusera frax.reserve "1 EOS" "deposit EOS" 51 | assert $(bc <<< "$? == 1") 52 | cleos push action everipediaiq transfer '["dcbtestusera", "frax.reserve", "1000.000 IQ", "deposit IQ"]' -p dcbtestusera 53 | assert $(bc <<< "$? == 1") 54 | cleos push action fraxtokenfxs transfer '["dcbtestusera", "frax.reserve", "1000.0000 FRAX", "deposit FRAX"]' -p dcbtestusera 55 | assert $(bc <<< "$? == 1") 56 | 57 | 58 | echo -e "${CYAN}-----------------------SET FULLY-BACKED TARGET-----------------------${NC}" 59 | cleos push action frax.reserve settarget '["2000.0000 USDT", "0.0000 FXS", 1e4]' -p frax.reserve 60 | assert $(bc <<< "$? == 0") 61 | 62 | echo -e "${CYAN}-----------------------BUY FRAX WITH USDT-----------------------${NC}" 63 | OLD_FRAX_BALANCE1=$(cleos get table fraxtokenfxs dcbtestusera accounts | jq '.rows[]' | grep FRAX | tr -d '"' | awk '{ print $2 }') 64 | OLD_FRAX_BALANCE2=$(cleos get table fraxtokenfxs dcbtestuserb accounts | jq '.rows[]' | grep FRAX | tr -d '"' | awk '{ print $2 }') 65 | OLD_USDT_BALANCE1=$(cleos get table frax.reserve dcbtestusera accounts | jq '.rows[]' | grep USDT | tr -d '"' | awk '{ print $2 }') 66 | OLD_USDT_BALANCE2=$(cleos get table frax.reserve dcbtestuserb accounts | jq '.rows[]' | grep USDT | tr -d '"' | awk '{ print $2 }') 67 | 68 | cleos push action frax.reserve buyfrax '["dcbtestusera", "1000.0000 FRAX"]' -p dcbtestusera 69 | assert $(bc <<< "$? == 0") 70 | cleos push action frax.reserve buyfrax '["dcbtestuserb", "1000.0000 FRAX"]' -p dcbtestuserb 71 | assert $(bc <<< "$? == 0") 72 | 73 | NEW_FRAX_BALANCE1=$(cleos get table fraxtokenfxs dcbtestusera accounts | jq '.rows[]' | grep FRAX | tr -d '"' | awk '{ print $2 }') 74 | NEW_FRAX_BALANCE2=$(cleos get table fraxtokenfxs dcbtestuserb accounts | jq '.rows[]' | grep FRAX | tr -d '"' | awk '{ print $2 }') 75 | NEW_USDT_BALANCE1=$(cleos get table frax.reserve dcbtestusera accounts | jq '.rows[]' | grep USDT | tr -d '"' | awk '{ print $2 }') 76 | NEW_USDT_BALANCE2=$(cleos get table frax.reserve dcbtestuserb accounts | jq '.rows[]' | grep USDT | tr -d '"' | awk '{ print $2 }') 77 | 78 | assert $(bc <<< "$NEW_FRAX_BALANCE1 - $OLD_FRAX_BALANCE1 == 1000") 79 | assert $(bc <<< "$NEW_FRAX_BALANCE2 - $OLD_FRAX_BALANCE2 == 1000") 80 | assert $(bc <<< "$OLD_USDT_BALANCE1 - $NEW_USDT_BALANCE1 == 1000") 81 | assert $(bc <<< "$OLD_USDT_BALANCE2 - $NEW_USDT_BALANCE2 == 1000") 82 | 83 | echo -e "${CYAN}-----------------------SET PARTIALLY-BACKED TARGET-----------------------${NC}" 84 | cleos push action frax.reserve settarget '["4000.0000 USDT", "10.0000 FXS", 1e4]' -p frax.reserve 85 | assert $(bc <<< "$? == 0") 86 | 87 | echo -e "${CYAN}-----------------------BUY FRAX WITH USDT + FXS-----------------------${NC}" 88 | OLD_FRAX_BALANCE1=$(cleos get table fraxtokenfxs dcbtestusera accounts | jq '.rows[]' | grep FRAX | tr -d '"' | awk '{ print $2 }') 89 | OLD_FRAX_BALANCE2=$(cleos get table fraxtokenfxs dcbtestuserb accounts | jq '.rows[]' | grep FRAX | tr -d '"' | awk '{ print $2 }') 90 | OLD_FXS_BALANCE1=$(cleos get table frax.reserve dcbtestusera accounts | jq '.rows[]' | grep FXS | tr -d '"' | awk '{ print $2 }') 91 | OLD_FXS_BALANCE2=$(cleos get table frax.reserve dcbtestuserb accounts | jq '.rows[]' | grep FXS | tr -d '"' | awk '{ print $2 }') 92 | 93 | cleos push action --force-unique frax.reserve buyfrax '["dcbtestusera", "1000.0000 FRAX"]' -p dcbtestusera 94 | assert $(bc <<< "$? == 0") 95 | cleos push action --force-unique frax.reserve buyfrax '["dcbtestuserb", "1000.0000 FRAX"]' -p dcbtestuserb 96 | assert $(bc <<< "$? == 0") 97 | 98 | NEW_FRAX_BALANCE1=$(cleos get table fraxtokenfxs dcbtestusera accounts | jq '.rows[]' | grep FRAX | tr -d '"' | awk '{ print $2 }') 99 | NEW_FRAX_BALANCE2=$(cleos get table fraxtokenfxs dcbtestuserb accounts | jq '.rows[]' | grep FRAX | tr -d '"' | awk '{ print $2 }') 100 | NEW_FXS_BALANCE1=$(cleos get table frax.reserve dcbtestusera accounts | jq '.rows[]' | grep FXS | tr -d '"' | awk '{ print $2 }') 101 | NEW_FXS_BALANCE2=$(cleos get table frax.reserve dcbtestuserb accounts | jq '.rows[]' | grep FXS | tr -d '"' | awk '{ print $2 }') 102 | 103 | 104 | assert $(bc <<< "$NEW_FRAX_BALANCE1 - $OLD_FRAX_BALANCE1 == 1000") 105 | assert $(bc <<< "$NEW_FRAX_BALANCE2 - $OLD_FRAX_BALANCE2 == 1000") 106 | assert $(bc <<< "$OLD_FXS_BALANCE1 > $NEW_FXS_BALANCE1") 107 | assert $(bc <<< "$OLD_FXS_BALANCE2 > $NEW_FXS_BALANCE2") 108 | 109 | 110 | echo -e "${CYAN}-----------------------SET BAD PRICE-----------------------${NC}" 111 | cleos push action frax.reserve settarget '["2000.0000 USDT", "0.0000 FXS", 0]' -p frax.reserve 112 | assert $(bc <<< "$? == 1") 113 | 114 | echo -e "${CYAN}-----------------------BAD FRAX PURCHASES-----------------------${NC}" 115 | # target already reached 116 | cleos push action frax.reserve buyfrax '["dcbtestuserb", "100.0000 FRAX"]' -p dcbtestuserb 117 | assert $(bc <<< "$? == 1") 118 | # not enough USDT 119 | cleos push action frax.reserve buyfrax '["dcbtestusera", "10000.0000 FRAX"]' -p dcbtestusera 120 | assert $(bc <<< "$? == 1") 121 | -------------------------------------------------------------------------------- /frax.loans/frax.loans.cpp: -------------------------------------------------------------------------------- 1 | #include "frax.loans.hpp" 2 | 3 | [[eosio::action]] 4 | void fraxloans::addtoken(name contract, symbol ticker) { 5 | require_auth( _self ); 6 | 7 | check(ticker.is_valid(), "invalid symbol name"); 8 | check(ticker.precision() == 4, "to simplify price calculations, only tokens with 4 decimal places are currently supported"); 9 | 10 | stats statstable(_self, _self.value); 11 | auto contract_sym_index = statstable.get_index(); 12 | uint128_t merged = merge_contract_symbol(contract, ticker); 13 | auto existing = contract_sym_index.find(merged); 14 | check(existing == contract_sym_index.end(), "Token is already registered"); 15 | check(statstable.find(ticker.code().raw()) == statstable.end(), "Another token with that ticker already exists"); 16 | 17 | statstable.emplace(_self, [&](auto& s) { 18 | s.contract = contract; 19 | s.available = asset(0, ticker); 20 | s.loaned = asset(0, ticker); 21 | s.price = asset(0, USDT_SYMBOL); 22 | s.allowed_as_collateral = true; 23 | s.can_deposit = true; 24 | }); 25 | } 26 | 27 | [[eosio::on_notify("*::transfer")]] 28 | void fraxloans::deposit( name from, name to, asset quantity, string memo ) { 29 | if (from == _self) return; // sending tokens, ignore 30 | 31 | auto symbol = quantity.symbol; 32 | check(symbol.is_valid(), "invalid symbol name"); 33 | check(to == _self, "stop trying to hack the contract"); 34 | check(is_account(from), "from account does not exist"); 35 | check(is_account(to), "to account does not exist"); 36 | 37 | // make sure contract and symbol are accepted by contract 38 | stats statstable(_self, _self.value); 39 | auto contract_sym_index = statstable.get_index(); 40 | uint128_t merged = merge_contract_symbol(get_first_receiver(), symbol); 41 | auto existing = contract_sym_index.find(merged); 42 | check(existing != contract_sym_index.end(), "Token is not yet supported"); 43 | 44 | // validate arguments 45 | check(quantity.is_valid(), "invalid quantity"); 46 | check(quantity.amount < 1e10, "quantity is suspiciously high. send a smaller amount"); 47 | check(quantity.amount > 0, "must deposit positive quantity"); 48 | check(memo.size() < 256, "memo must be less than 256 bytes"); 49 | 50 | // create/update entry in table 51 | accounts deptbl( _self, from.value ); 52 | auto account_it = deptbl.find(symbol.code().raw()); 53 | if (account_it == deptbl.end()) { 54 | deptbl.emplace( _self, [&](auto& a) { 55 | a.balance = quantity; 56 | a.last_updated = current_time_point().sec_since_epoch(); 57 | }); 58 | } 59 | else { 60 | deptbl.modify( account_it, _self, [&](auto& a) { 61 | a.balance += quantity; 62 | a.last_updated = current_time_point().sec_since_epoch(); 63 | }); 64 | } 65 | 66 | // update stats 67 | contract_sym_index.modify( existing, _self, [&](auto& s) { 68 | s.available += quantity; 69 | }); 70 | 71 | } 72 | 73 | [[eosio::action]] 74 | void fraxloans::borrow(name borrower, asset quantity) { 75 | require_auth(borrower); 76 | 77 | check(quantity.amount > 0, "Must borrow positive amount"); 78 | 79 | // Check ticker is borrowable 80 | stats statstbl( _self, _self.value ); 81 | auto& stat_it = statstbl.get(quantity.symbol.code().raw(), "Token is not supported"); 82 | check(stat_it.available > quantity, "Not enough supply available for requested quantity"); 83 | 84 | // Check if sufficient collateral is present to back loan 85 | // NOTE: Both sum_collateral and sum_borrow are in units 1e-8 USDT 86 | accounts acctstbl( _self, borrower.value ); 87 | auto account_it = acctstbl.begin(); 88 | uint64_t sum_collateral = 0; 89 | while (account_it != acctstbl.end()) { 90 | auto token_price_it = statstbl.get(account_it->balance.symbol.code().raw(), "Token is not supported"); 91 | if (!token_price_it.allowed_as_collateral) continue; 92 | sum_collateral += account_it->balance.amount * token_price_it.price.amount; 93 | account_it++; 94 | } 95 | uint64_t sum_borrow = quantity.amount * stat_it.price.amount; 96 | while (account_it != acctstbl.end()) { 97 | auto token_price_it = statstbl.get(account_it->balance.symbol.code().raw(), "Token is not supported"); 98 | sum_borrow += account_it->borrowing.amount * token_price_it.price.amount; 99 | account_it++; 100 | } 101 | check((static_cast(sum_collateral * COLLATERAL_RATIO) > sum_borrow), "Insufficient collateral to back loan"); 102 | 103 | // Update supply 104 | statstbl.modify( stat_it, _self, [&](auto s) { 105 | s.available -= quantity; 106 | s.loaned += quantity; 107 | }); 108 | 109 | 110 | // Update borrower account 111 | account_it = acctstbl.find(quantity.symbol.code().raw()); 112 | if (account_it == acctstbl.end()) { 113 | acctstbl.emplace( _self, [&](auto& a) { 114 | a.balance = quantity; 115 | a.borrowing = quantity; 116 | }); 117 | } 118 | else { 119 | acctstbl.modify( account_it, _self, [&](auto& a) { 120 | a.balance += quantity; 121 | a.borrowing += quantity; 122 | }); 123 | } 124 | } 125 | 126 | [[eosio::action]] 127 | void fraxloans::repay(name borrower, asset quantity) { 128 | require_auth(borrower); 129 | 130 | check(quantity.amount > 0, "Must repay positive amount"); 131 | 132 | // Check ticker is borrowable 133 | stats statstbl( _self, _self.value ); 134 | auto stat_it = statstbl.get(quantity.symbol.code().raw(), "Token is not supported"); 135 | 136 | // Update supply 137 | statstbl.modify( stat_it, _self, [&](auto& s) { 138 | s.available += quantity; 139 | s.loaned -= quantity; 140 | }); 141 | 142 | 143 | // Update borrower account 144 | accounts acctstbl( _self, borrower.value ); 145 | auto account_it = acctstbl.find(quantity.symbol.code().raw()); 146 | check(account_it != acctstbl.end(), "No borrow balance found for this user"); 147 | check(account_it->borrowing >= quantity, "Attempting to repay too much"); 148 | acctstbl.modify( account_it, _self, [&](auto& a) { 149 | a.balance -= quantity; 150 | a.borrowing -= quantity; 151 | }); 152 | } 153 | 154 | [[eosio::action]] 155 | void fraxloans::setprice(asset price) { 156 | require_auth( _self ); 157 | 158 | stats statstable(_self, _self.value); 159 | auto stats_it = statstable.find(price.symbol.code().raw()); 160 | check(stats_it != statstable.end(), "symbol is not supported. check decimal places"); 161 | 162 | statstable.modify( stats_it, _self, [&](auto &s) { 163 | s.price = price; 164 | }); 165 | 166 | } 167 | 168 | //[[eosio::action]] 169 | //void liquidate(name user, name executor) { 170 | // Check if sufficient collateral is present to back loan 171 | // NOTE: Both sum_collateral and sum_borrow are in units 1e-8 USDT 172 | // accounts acctstbl( _self, user.value ); 173 | // auto account_it = acctstbl.begin(); 174 | // uint64_t sum_collateral = 0; 175 | // while (account_it != acctstbl.end()) { 176 | // auto token_price_it = statstbl.get(account_it->balance.symbol.code().raw(), "Token is not supported"); 177 | // if (!token_price_it->allowed_as_collateral) continue; 178 | // sum_collateral += account_it->balance.amount * token_price_it->price.amount; 179 | // account_it++; 180 | // } 181 | // uint64_t sum_borrow = quantity.amount * stat_it->price.amount; 182 | // while (account_it != acctstbl.end()) { 183 | // auto token_price_it = statstbl.get(account_it->balance.symbol.code().raw(), "Token is not supported"); 184 | // sum_borrow += account_it->borrowing.amount * token_price_it->price.amount; 185 | // account_it++; 186 | // } 187 | // check((static_cast(sum_collateral * COLLATERAL_RATIO) < sum_borrow), "Loans are sufficiently backed"); 188 | // 189 | // // TODO: Send to auction contract 190 | // 191 | //} 192 | -------------------------------------------------------------------------------- /bank.cdp/bank.cdp.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * @ author 4 | * richard tiutiun 5 | * @ copyright 6 | * defined in ../README.md 7 | * @ file 8 | * contract header for CDP engine 9 | */ 10 | #pragma once 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace eosio; 17 | using std::make_tuple; 18 | using std::string; 19 | 20 | CONTRACT bankcdp : public contract 21 | { using contract::contract; 22 | public: 23 | static constexpr uint32_t SECYR = 10; //31557600; // TODO: Secs per avf year 24 | static constexpr uint32_t FEED_FRESH = 300; // Seconds in a 5 minute period 25 | static constexpr uint32_t VOTE_PERIOD = 5; //604800; //TODO: Secs per week 26 | const symbol IQ_SYMBOL = symbol( "IQ", 3 ); 27 | const name IQ_NAME = name( "everipediaiq" ); 28 | 29 | /* The owner of an urn can transfer 30 | * its ownership at any time using give. 31 | */ //ACTION give( name giver, name taker, symbol_code symbl ); 32 | 33 | /* Global settlement: 34 | * The system uses the market price of collateral 35 | * at the time of settlement to compute how much 36 | * collateral each user gets. 37 | */ ACTION settle( name feeder, symbol_code symbl ); 38 | 39 | /* Publish a proposal that either motions for the 40 | * enactment of a new CDP type, or modification 41 | * of an existing one. 42 | */ ACTION propose( name proposer, symbol_code symbl, 43 | symbol clatrl, symbol_code stabl, 44 | uint64_t max, uint64_t gmax, 45 | uint64_t pen, uint64_t fee, 46 | uint64_t beg, uint64_t liq, 47 | uint32_t tau, uint32_t ttl, 48 | name feeder, name contract ); 49 | 50 | /* Take a position (for/against) on a CDP proposal 51 | */ ACTION vote( name voter, symbol_code symbl, 52 | bool against, asset quantity ); 53 | 54 | /* Called either automatically after VOTE_PERIOD from the moment 55 | * of proposal via "propose", via deferred action with proposer's 56 | * auth, or (if deferred action fails) may be called directly by 57 | * proposer after VOTE_PERIOD has passed. Proposal may be enacted 58 | * if there are more votes in favor than against. Cleanup must be 59 | * done regardless on relevant multi_index tables. 60 | */ ACTION referended( name proposer, symbol_code symbl ); 61 | 62 | /* liquify action 63 | * If the collateral value in a CDP drops below 150% of the outstanding stablecoin, 64 | * the contract automatically sells enough of your collateral to buy back as 65 | * many stablecoin as you issued. The issued stablecoin is thus taken out of circulation. Similar to a margin call. 66 | */ ACTION liquify( name bidder, name owner, 67 | symbol_code symbl, asset bidamt ); 68 | 69 | /* Unless CDP is in liquidation, 70 | * its owner can use lock to lock 71 | * more collateral. 72 | */ ACTION lock( name owner, symbol_code symbl, asset quantity ); 73 | 74 | /* Reclaims collateral from an overcollateralized CDP, 75 | * without taking the CDP below its liquidation ratio. 76 | */ ACTION bail( name owner, symbol_code symbl, asset quantity ); 77 | 78 | /* Issue fresh stablecoin from this CDP. 79 | */ ACTION draw( name owner, symbol_code symbl, asset quantity ); 80 | 81 | /* Owner can send back stablecoin and reduce 82 | * the CDP's issued stablecoin balance. 83 | */ ACTION wipe( name owner, symbol_code symbl, asset quantity ); 84 | 85 | /* Owner can close this CDP, if the price feed 86 | * is up to date and the CDP is not in liquidation. 87 | * Reclaims all collateral and cancels all issuance 88 | * plus fee. 89 | */ ACTION shut( name owner, symbol_code symbl ); 90 | 91 | /* Price feed data update action 92 | */ ACTION upfeed( name feeder, asset price, 93 | symbol_code cdp_type, symbol symbl ); 94 | 95 | // Open CDP or initiate balances for account 96 | ACTION open( name owner, symbol_code symbl, name ram_payer ); 97 | 98 | // NEED DESCRIPTIONS FOR THE FUNCTIONS BELOW 99 | // NEED DESCRIPTIONS FOR THE FUNCTIONS BELOW 100 | // NEED DESCRIPTIONS FOR THE FUNCTIONS BELOW 101 | 102 | ACTION withdraw( name owner, asset quantity, string memo ); 103 | 104 | // Close balance of given symbol for account 105 | ACTION close( name owner, symbol_code symbl ); 106 | 107 | ACTION deposit( name from, name to, 108 | asset quantity, string memo ); 109 | 110 | ACTION transfer( name from, name to, 111 | asset quantity, string memo ); 112 | 113 | static asset get_balance( name contract, symbol_code sym_code, name owner ) 114 | { accounts accountstable( contract, sym_code.raw() ); 115 | const auto& ac = accountstable.get( owner.value ); 116 | return ac.balance; 117 | } 118 | 119 | private: 120 | TABLE bid //SCOPE: CDP type symbol 121 | { name owner; 122 | name bidder; 123 | asset bidamt; 124 | 125 | uint32_t started; 126 | uint32_t lastbid; 127 | 128 | uint64_t primary_key() const { return owner.value; } 129 | }; typedef eosio::multi_index< "bid"_n, bid > bids; 130 | 131 | TABLE cdp // SCOPE: CDP type symbol 132 | { name owner; 133 | uint32_t created; 134 | asset collateral; // Amount of collateral currently locked by this CDP 135 | asset stablecoin; // Stablecoin issued 136 | bool live = true; // In liquidation or not 137 | 138 | uint64_t primary_key() const { return owner.value; } 139 | }; typedef eosio::multi_index< "cdp"_n, cdp > cdps; 140 | 141 | TABLE prop 142 | { symbol_code cdp_type; 143 | uint32_t deadline; 144 | name proposer; 145 | asset yay; 146 | asset nay; 147 | 148 | uint64_t primary_key() const { return cdp_type.raw(); } 149 | }; typedef eosio::multi_index< "prop"_n, prop > props; 150 | 151 | TABLE stat //SCOPE: Either _self or proposer 152 | { bool live = false; 153 | uint32_t last_vote = 0; 154 | uint32_t tau; // Auctions will terminate after tau seconds have passed from start 155 | uint32_t ttl; // And after ttl seconds have passed since placement of last bid 156 | 157 | //TODO: Feeders could be vector of accounts 158 | name feeder; // Designated account for providing price feeds 159 | symbol_code cdp_type; // CDT Type Symbol e.g... DBEOS / DBKARMA...24*23*22*21*20 = over 5M different variants 160 | uint64_t global_ceil; // Max total stablecoin issuable by all CDPs of this type 161 | uint64_t debt_ceiling; 162 | uint64_t stability_fee; // Units are APR % 163 | uint64_t beg; // Minimum bid increase in % 164 | uint64_t penalty_ratio; // By default, 13% of the collateral in the CDP. Units are % 165 | uint64_t liquid8_ratio; // Collateral asset units needed per issued stable tokens. Units are % 166 | asset fee_balance; // Total stability fees paid 167 | asset total_stablecoin; // Total amount of stablecoin in circulation for CDPs of this type 168 | extended_asset total_collateral; // Total amount locked as collateral for all CDPs of this type 169 | 170 | uint64_t primary_key()const { return cdp_type.raw(); } 171 | }; typedef eosio::multi_index< "stat"_n, stat > stats; 172 | 173 | TABLE feed 174 | { asset total; // Amount in circulation, not locked in CDPs 175 | asset price; 176 | uint32_t stamp; 177 | 178 | uint64_t primary_key() const { return total.symbol.code().raw(); } 179 | }; typedef eosio::multi_index< "feed"_n, feed > feeds; 180 | 181 | TABLE account //SCOPE: Balance symbol 182 | { asset balance; // Can be proposed CDP type symbol voted on 183 | name owner; 184 | name code; 185 | 186 | uint64_t primary_key() const { return owner.value; } 187 | }; typedef eosio::multi_index< "accounts"_n, account > accounts; 188 | 189 | name sub_balance( name owner, asset value ); // Returns balance contract 190 | void add_balance( name owner, asset value, name code ); 191 | }; 192 | -------------------------------------------------------------------------------- /bank.pay2key/bank.pay2key.cpp: -------------------------------------------------------------------------------- 1 | #include "bank.pay2key.hpp" 2 | #include "base58.c" 3 | 4 | [[eosio::action]] 5 | void pay2key::create(name token_contract, symbol ticker) { 6 | require_auth( _self ); 7 | 8 | check(ticker.is_valid(), "invalid symbol name"); 9 | 10 | stats statstable(_self, _self.value); 11 | auto contract_sym_index = statstable.get_index(); 12 | uint128_t merged = merge_contract_symbol(token_contract, ticker); 13 | auto existing = contract_sym_index.find(merged); 14 | check(existing == contract_sym_index.end(), "Token is already registered"); 15 | 16 | asset supply = asset(0, ticker); 17 | 18 | statstable.emplace(_self, [&](auto& s) { 19 | s.chain_id = statstable.available_primary_key(); 20 | s.symbol = ticker; 21 | s.token_contract = token_contract; 22 | s.supply = supply; 23 | }); 24 | } 25 | 26 | void pay2key::issue( name from, name to, asset quantity, string memo ) { 27 | if (from == _self) return; // sending tokens, ignore 28 | 29 | auto symbol = quantity.symbol; 30 | check(symbol.is_valid(), "invalid symbol name"); 31 | check(memo.size() == 53, "memo must be a 53-char EOS public key"); 32 | check(memo.substr(0,3) == "EOS", "public key must start with EOS"); 33 | check(to == _self, "stop trying to hack the contract"); 34 | 35 | // make sure contract and symbol are accepted by contract 36 | stats statstable(_self, _self.value); 37 | auto contract_sym_index = statstable.get_index(); 38 | uint128_t merged = merge_contract_symbol(get_first_receiver(), symbol); 39 | auto existing = contract_sym_index.find(merged); 40 | check(existing != contract_sym_index.end(), "Token is not yet supported. You must assign it a chain_id with `create` first"); 41 | const auto& st = *existing; 42 | 43 | // validate arguments 44 | check(quantity.is_valid(), "invalid quantity"); 45 | check(quantity.amount > 0, "must issue positive quantity"); 46 | 47 | // TODO: ensure token balance is enough to cover UTXO issuance 48 | // This will always be true unless the contract has been hacked 49 | // so it is mostly a sanity check 50 | 51 | statstable.modify(st, same_payer, [&](auto& s) { 52 | s.supply += quantity; 53 | }); 54 | 55 | // convert public key memo to public_key object 56 | public_key issue_to; 57 | size_t issue_to_len = 37; 58 | b58tobin((void *)issue_to.data.data(), &issue_to_len, memo.substr(3).c_str()); 59 | 60 | // validate the checksum 61 | public_key issue_to_copy = issue_to; 62 | checksum160 checksum = ripemd160((const char *)issue_to_copy.data.begin(), 33); 63 | std::array checksum_bytes = checksum.extract_as_byte_array(); 64 | for (int i=0; i<4; i++) 65 | check(checksum_bytes[i] == (uint8_t)issue_to.data[33+i], "invalid public key in memo: checksum does not validate"); 66 | 67 | // Cannot charge RAM to other accounts during notify 68 | // This is a major issue. How can we get the sender to pay for their own RAM? 69 | add_balance(st.chain_id, issue_to, quantity, _self); 70 | } 71 | 72 | [[eosio::action]] 73 | void pay2key::transfer( 74 | uint64_t chain_id, 75 | name relayer_account, 76 | public_key relayer, 77 | public_key from, 78 | public_key to, 79 | asset quantity, 80 | asset fee, 81 | uint64_t nonce, 82 | string memo, 83 | signature sig) { 84 | 85 | // get currency information 86 | stats statstable(_self, _self.value); 87 | const auto st = statstable.get(chain_id, "no token found for chain_id. chain_id must be created first"); 88 | 89 | // verify symbol matches currency information 90 | check(st.symbol == quantity.symbol, "quantity and chain_id symbols don't match. check decimal places"); 91 | check(st.symbol == fee.symbol, "fee and chain_id symbols don't match. check decimal places"); 92 | 93 | // get last nonce 94 | accounts accounts_table(_self, chain_id); 95 | auto pk_index = accounts_table.get_index(); 96 | auto account_it = pk_index.find(public_key_to_fixed_bytes(from)); 97 | uint64_t last_nonce = 0; 98 | if (account_it != pk_index.end()) 99 | last_nonce = account_it->last_nonce; 100 | 101 | // validate inputs 102 | check(from != to, "cannot transfer to self"); 103 | check(quantity.is_valid(), "invalid quantity" ); 104 | check(fee.is_valid(), "invalid quantity" ); 105 | check(quantity.amount > 0, "must transfer positive quantity"); 106 | check(fee.amount >= 0, "fee must be non-negative"); 107 | check(quantity.amount <= account_it->balance.amount, "user has insufficient balance"); 108 | check(quantity.amount + fee.amount <= account_it->balance.amount, "user has insufficient balance to cover fee"); 109 | check(memo.size() <= 159, "memo has more than 159 bytes"); 110 | check(nonce > last_nonce, "Nonce must be greater than last nonce. This transaction may already have been relayed."); 111 | check(nonce < last_nonce + 100, "Nonce cannot jump by more than 100"); 112 | 113 | // transaction format 114 | // bytes field 115 | // 1 version 116 | // 1 length 117 | // 4 chain_id 118 | // 33 from_pubkey 119 | // 33 to_pubkey 120 | // 8 quantity 121 | // 8 fee 122 | // 8 nonce 123 | // 0-159 memo 124 | // tx meta fields 125 | uint8_t version = 0x02; 126 | uint8_t length = 96 + memo.size(); 127 | uint32_t chain_id_32 = chain_id & 0xFFFFFFFF; 128 | 129 | // construct raw transaction 130 | uint8_t rawtx[length]; 131 | rawtx[0] = version; 132 | rawtx[1] = length; 133 | memcpy(rawtx + 2, (uint8_t *)&chain_id, 4); 134 | memcpy(rawtx + 6, from.data.data(), 33); 135 | memcpy(rawtx + 39, to.data.data(), 33); 136 | memcpy(rawtx + 72, (uint8_t *)&quantity.amount, 8); 137 | memcpy(rawtx + 80, (uint8_t *)&fee.amount, 8); 138 | memcpy(rawtx + 88, (uint8_t *)&nonce, 8); 139 | memcpy(rawtx + 96, memo.c_str(), memo.size()); 140 | 141 | // hash transaction 142 | checksum256 digest = sha256((const char *)rawtx, length); 143 | 144 | // verify signature 145 | assert_recover_key(digest, sig, from); 146 | 147 | // update last nonce 148 | pk_index.modify(account_it, same_payer, [&]( auto& n ){ 149 | n.last_nonce = nonce; 150 | }); 151 | 152 | // always subtract the quantity from the sender 153 | sub_balance(chain_id, from, quantity); 154 | 155 | // Create the public_key object for the WITHDRAW_ADDRESS 156 | public_key withdraw_key = to; 157 | memcpy(withdraw_key.data.data(), WITHDRAW_KEY_BYTES, 33); 158 | 159 | // if the to address is the withdraw address, send an IQ transfer out 160 | // and update the circulating supply 161 | if (to == withdraw_key) { 162 | name withdraw_account; 163 | std::string withdraw_memo; 164 | uint64_t colon_index = memo.find(":"); 165 | if (colon_index == std::string::npos) { 166 | withdraw_account = name(memo); 167 | withdraw_memo = std::string(""); 168 | } 169 | else { 170 | withdraw_account = name(memo.substr(0,colon_index)); 171 | if (colon_index == memo.size() - 1) // edge case where there's nothing after the colon 172 | withdraw_memo = ""; 173 | else 174 | withdraw_memo = memo.substr(colon_index + 1); 175 | } 176 | 177 | action( 178 | permission_level{ _self , name("active") }, 179 | st.token_contract , name("transfer"), 180 | std::make_tuple( _self, withdraw_account, quantity, withdraw_memo) 181 | ).send(); 182 | 183 | auto st = statstable.find(chain_id); 184 | statstable.modify(st, same_payer, [&](auto& s) { 185 | s.supply -= quantity; 186 | }); 187 | } 188 | // add the balance if it's not a withdrawal 189 | else { 190 | add_balance(chain_id, to, quantity, relayer_account); 191 | } 192 | 193 | // update balances with fees 194 | if (fee.amount > 0) { 195 | sub_balance(chain_id, from, fee); 196 | add_balance(chain_id, relayer, fee, relayer_account); 197 | } 198 | 199 | } 200 | 201 | void pay2key::sub_balance(uint64_t chain_id, public_key sender, asset value) { 202 | accounts from_acts(_self, chain_id); 203 | 204 | auto accounts_index = from_acts.get_index(); 205 | const auto& from = accounts_index.get(public_key_to_fixed_bytes(sender), "no public key object found"); 206 | check(from.balance.amount >= value.amount, "overdrawn balance"); 207 | 208 | if (from.balance.amount == value.amount) { 209 | from_acts.erase(from); 210 | } else { 211 | from_acts.modify(from, same_payer, [&]( auto& a ) { 212 | a.balance -= value; 213 | }); 214 | } 215 | } 216 | 217 | void pay2key::add_balance(uint64_t chain_id, public_key recipient, asset value, name ram_payer) { 218 | accounts to_acts(_self, chain_id); 219 | 220 | auto accounts_index = to_acts.get_index(); 221 | auto to = accounts_index.find(public_key_to_fixed_bytes(recipient)); 222 | 223 | if (to == accounts_index.end()) { 224 | to_acts.emplace(ram_payer, [&]( auto& a ){ 225 | a.key = to_acts.available_primary_key(); 226 | a.balance = value; 227 | a.publickey = recipient; 228 | a.last_nonce = 0; 229 | }); 230 | } else { 231 | accounts_index.modify(to, same_payer, [&]( auto& a ) { 232 | a.balance += value; 233 | }); 234 | } 235 | } 236 | 237 | extern "C" void apply(uint64_t receiver, uint64_t code, uint64_t action) 238 | { 239 | auto _self = receiver; 240 | if (code != _self && action == name("transfer").value) 241 | { 242 | eosio::execute_action( 243 | eosio::name(receiver), eosio::name(code), &pay2key::issue 244 | ); 245 | } 246 | else if (code == _self && action == name("create").value) 247 | { 248 | eosio::execute_action( 249 | eosio::name(receiver), eosio::name(code), &pay2key::create 250 | ); 251 | } 252 | else if (code == _self && action == name("transfer").value) 253 | { 254 | eosio::execute_action( 255 | eosio::name(receiver), eosio::name(code), &pay2key::transfer 256 | ); 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /bank.pay2key/js_test/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js_test", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "balanced-match": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 10 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 11 | "dev": true 12 | }, 13 | "base-x": { 14 | "version": "3.0.5", 15 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz", 16 | "integrity": "sha1-062lmv7QW5IatYHsMRLmREugeVo=", 17 | "requires": { 18 | "safe-buffer": "^5.0.1" 19 | } 20 | }, 21 | "bigi": { 22 | "version": "1.4.2", 23 | "resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", 24 | "integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU=" 25 | }, 26 | "brace-expansion": { 27 | "version": "1.1.11", 28 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 29 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 30 | "dev": true, 31 | "requires": { 32 | "balanced-match": "^1.0.0", 33 | "concat-map": "0.0.1" 34 | } 35 | }, 36 | "browserify-aes": { 37 | "version": "1.2.0", 38 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 39 | "integrity": "sha1-Mmc0ZC9APavDADIJhTu3CtQo70g=", 40 | "requires": { 41 | "buffer-xor": "^1.0.3", 42 | "cipher-base": "^1.0.0", 43 | "create-hash": "^1.1.0", 44 | "evp_bytestokey": "^1.0.3", 45 | "inherits": "^2.0.1", 46 | "safe-buffer": "^5.0.1" 47 | } 48 | }, 49 | "bs58": { 50 | "version": "4.0.1", 51 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 52 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 53 | "requires": { 54 | "base-x": "^3.0.2" 55 | } 56 | }, 57 | "buffer-xor": { 58 | "version": "1.0.3", 59 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 60 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" 61 | }, 62 | "bytebuffer": { 63 | "version": "5.0.1", 64 | "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", 65 | "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", 66 | "requires": { 67 | "long": "~3" 68 | } 69 | }, 70 | "cipher-base": { 71 | "version": "1.0.4", 72 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 73 | "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", 74 | "requires": { 75 | "inherits": "^2.0.1", 76 | "safe-buffer": "^5.0.1" 77 | } 78 | }, 79 | "concat-map": { 80 | "version": "0.0.1", 81 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 82 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 83 | "dev": true 84 | }, 85 | "create-hash": { 86 | "version": "1.2.0", 87 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 88 | "integrity": "sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY=", 89 | "requires": { 90 | "cipher-base": "^1.0.1", 91 | "inherits": "^2.0.1", 92 | "md5.js": "^1.3.4", 93 | "ripemd160": "^2.0.1", 94 | "sha.js": "^2.4.0" 95 | } 96 | }, 97 | "create-hmac": { 98 | "version": "1.1.7", 99 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 100 | "integrity": "sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8=", 101 | "requires": { 102 | "cipher-base": "^1.0.3", 103 | "create-hash": "^1.1.0", 104 | "inherits": "^2.0.1", 105 | "ripemd160": "^2.0.0", 106 | "safe-buffer": "^5.0.1", 107 | "sha.js": "^2.4.8" 108 | } 109 | }, 110 | "ecurve": { 111 | "version": "1.0.6", 112 | "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", 113 | "integrity": "sha1-39q7txSfjYt4gWvlp9W4P89t55c=", 114 | "requires": { 115 | "bigi": "^1.1.0", 116 | "safe-buffer": "^5.0.1" 117 | } 118 | }, 119 | "eosjs-ecc": { 120 | "version": "4.0.4", 121 | "resolved": "https://registry.npmjs.org/eosjs-ecc/-/eosjs-ecc-4.0.4.tgz", 122 | "integrity": "sha1-QxRQ8wpvcwiP9de6Hr3+lnpcpKs=", 123 | "requires": { 124 | "bigi": "^1.4.2", 125 | "browserify-aes": "^1.0.6", 126 | "bs58": "^4.0.1", 127 | "bytebuffer": "^5.0.1", 128 | "create-hash": "^1.1.3", 129 | "create-hmac": "^1.1.6", 130 | "ecurve": "^1.0.5", 131 | "randombytes": "^2.0.5" 132 | } 133 | }, 134 | "evp_bytestokey": { 135 | "version": "1.0.3", 136 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 137 | "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", 138 | "requires": { 139 | "md5.js": "^1.3.4", 140 | "safe-buffer": "^5.1.1" 141 | } 142 | }, 143 | "fs.realpath": { 144 | "version": "1.0.0", 145 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 146 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 147 | "dev": true 148 | }, 149 | "glob": { 150 | "version": "7.1.3", 151 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 152 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 153 | "dev": true, 154 | "requires": { 155 | "fs.realpath": "^1.0.0", 156 | "inflight": "^1.0.4", 157 | "inherits": "2", 158 | "minimatch": "^3.0.4", 159 | "once": "^1.3.0", 160 | "path-is-absolute": "^1.0.0" 161 | } 162 | }, 163 | "hash-base": { 164 | "version": "3.0.4", 165 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", 166 | "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", 167 | "requires": { 168 | "inherits": "^2.0.1", 169 | "safe-buffer": "^5.0.1" 170 | } 171 | }, 172 | "inflight": { 173 | "version": "1.0.6", 174 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 175 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 176 | "dev": true, 177 | "requires": { 178 | "once": "^1.3.0", 179 | "wrappy": "1" 180 | } 181 | }, 182 | "inherits": { 183 | "version": "2.0.3", 184 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 185 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 186 | }, 187 | "interpret": { 188 | "version": "1.2.0", 189 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", 190 | "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", 191 | "dev": true 192 | }, 193 | "long": { 194 | "version": "3.2.0", 195 | "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", 196 | "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" 197 | }, 198 | "md5.js": { 199 | "version": "1.3.5", 200 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", 201 | "integrity": "sha1-tdB7jjIW4+J81yjXL3DR5qNCAF8=", 202 | "requires": { 203 | "hash-base": "^3.0.0", 204 | "inherits": "^2.0.1", 205 | "safe-buffer": "^5.1.2" 206 | } 207 | }, 208 | "minimatch": { 209 | "version": "3.0.4", 210 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 211 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 212 | "dev": true, 213 | "requires": { 214 | "brace-expansion": "^1.1.7" 215 | } 216 | }, 217 | "once": { 218 | "version": "1.4.0", 219 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 220 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 221 | "dev": true, 222 | "requires": { 223 | "wrappy": "1" 224 | } 225 | }, 226 | "path-is-absolute": { 227 | "version": "1.0.1", 228 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 229 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 230 | "dev": true 231 | }, 232 | "path-parse": { 233 | "version": "1.0.6", 234 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 235 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 236 | "dev": true 237 | }, 238 | "randombytes": { 239 | "version": "2.0.6", 240 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", 241 | "integrity": "sha1-0wLFIpSFiISKjTAMkytEwkIx2oA=", 242 | "requires": { 243 | "safe-buffer": "^5.1.0" 244 | } 245 | }, 246 | "rechoir": { 247 | "version": "0.6.2", 248 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 249 | "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", 250 | "dev": true, 251 | "requires": { 252 | "resolve": "^1.1.6" 253 | } 254 | }, 255 | "resolve": { 256 | "version": "1.10.0", 257 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", 258 | "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", 259 | "dev": true, 260 | "requires": { 261 | "path-parse": "^1.0.6" 262 | } 263 | }, 264 | "ripemd160": { 265 | "version": "2.0.2", 266 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 267 | "integrity": "sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw=", 268 | "requires": { 269 | "hash-base": "^3.0.0", 270 | "inherits": "^2.0.1" 271 | } 272 | }, 273 | "safe-buffer": { 274 | "version": "5.1.2", 275 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 276 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 277 | }, 278 | "sha.js": { 279 | "version": "2.4.11", 280 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 281 | "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", 282 | "requires": { 283 | "inherits": "^2.0.1", 284 | "safe-buffer": "^5.0.1" 285 | } 286 | }, 287 | "shelljs": { 288 | "version": "0.8.3", 289 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", 290 | "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", 291 | "dev": true, 292 | "requires": { 293 | "glob": "^7.0.0", 294 | "interpret": "^1.0.0", 295 | "rechoir": "^0.6.2" 296 | } 297 | }, 298 | "wrappy": { 299 | "version": "1.0.2", 300 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 301 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 302 | "dev": true 303 | } 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /tests/bootstrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Kedar Iyer (mostly) and Travis Moore 4 | 5 | CYAN='\033[1;36m' 6 | NC='\033[0m' 7 | 8 | trap ctrl_c INT 9 | function ctrl_c { 10 | exit 11; 11 | } 12 | 13 | RECOMPILE_AND_RESET_EOSIO_CONTRACTS=0 14 | HELP=0 15 | EOSIO_CONTRACTS_ROOT=/home/kedar/eosio.contracts/build/contracts/ 16 | NODEOS_HOST="127.0.0.1" 17 | NODEOS_PROTOCOL="http" 18 | NODEOS_PORT="8888" 19 | NODEOS_LOCATION="${NODEOS_PROTOCOL}://${NODEOS_HOST}:${NODEOS_PORT}" 20 | 21 | alias cleos="cleos --url=${NODEOS_LOCATION}" 22 | 23 | ####################################### 24 | ## HELPERS 25 | 26 | # function balance { 27 | # cleos get table bank.token $1 accounts | jq ".rows[0].balance" | tr -d '"' | awk '{print $1}' 28 | # } 29 | 30 | assert () 31 | { 32 | 33 | if [ $1 -eq 0 ]; then 34 | FAIL_LINE=$( caller | awk '{print $1}') 35 | echo -e "Assertion failed. Line $FAIL_LINE:" 36 | head -n $FAIL_LINE $BASH_SOURCE | tail -n 1 37 | exit 99 38 | fi 39 | } 40 | 41 | ipfsgen () { 42 | echo -e "Qm$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 44 | head -n 1)" 43 | } 44 | 45 | # Don't allow tests on mainnet 46 | CHAIN_ID=$(cleos get info | jq ".chain_id" | tr -d '"') 47 | if [ $CHAIN_ID = "aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906" ]; then 48 | >&2 echo -e "Cannot run test on mainnet" 49 | exit 1 50 | fi 51 | 52 | # Create BIOS accounts 53 | rm ~/eosio-wallet/default.wallet 54 | cleos wallet create --to-console 55 | 56 | # EOSIO system-related keys 57 | echo -e "${CYAN}-----------------------SYSTEM KEYS-----------------------${NC}" 58 | cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 59 | cleos wallet import --private-key 5JgqWJYVBcRhviWZB3TU1tN9ui6bGpQgrXVtYZtTG2d3yXrDtYX 60 | cleos wallet import --private-key 5JjjgrrdwijEUU2iifKF94yKduoqfAij4SKk6X5Q3HfgHMS4Ur6 61 | cleos wallet import --private-key 5HxJN9otYmhgCKEbsii5NWhKzVj2fFXu3kzLhuS75upN5isPWNL 62 | cleos wallet import --private-key 5JNHjmgWoHiG9YuvX2qvdnmToD2UcuqavjRW5Q6uHTDtp3KG3DS 63 | cleos wallet import --private-key 5JZkaop6wjGe9YY8cbGwitSuZt8CjRmGUeNMPHuxEDpYoVAjCFZ 64 | cleos wallet import --private-key 5Hroi8WiRg3by7ap3cmnTpUoqbAbHgz3hGnGQNBYFChswPRUt26 65 | cleos wallet import --private-key 5JbMN6pH5LLRT16HBKDhtFeKZqe7BEtLBpbBk5D7xSZZqngrV8o 66 | cleos wallet import --private-key 5JUoVWoLLV3Sj7jUKmfE8Qdt7Eo7dUd4PGZ2snZ81xqgnZzGKdC 67 | cleos wallet import --private-key 5Ju1ree2memrtnq8bdbhNwuowehZwZvEujVUxDhBqmyTYRvctaF 68 | 69 | # Create system accounts 70 | echo -e "${CYAN}-----------------------SYSTEM ACCOUNTS-----------------------${NC}" 71 | cleos create account eosio eosio.bpay EOS7gFoz5EB6tM2HxdV9oBjHowtFipigMVtrSZxrJV3X6Ph4jdPg3 72 | cleos create account eosio eosio.msig EOS6QRncHGrDCPKRzPYSiWZaAw7QchdKCMLWgyjLd1s2v8tiYmb45 73 | cleos create account eosio eosio.names EOS7ygRX6zD1sx8c55WxiQZLfoitYk2u8aHrzUxu6vfWn9a51iDJt 74 | cleos create account eosio eosio.ram EOS5tY6zv1vXoqF36gUg5CG7GxWbajnwPtimTnq6h5iptPXwVhnLC 75 | cleos create account eosio eosio.ramfee EOS6a7idZWj1h4PezYks61sf1RJjQJzrc8s4aUbe3YJ3xkdiXKBhF 76 | cleos create account eosio eosio.saving EOS8ioLmKrCyy5VyZqMNdimSpPjVF2tKbT5WKhE67vbVPcsRXtj5z 77 | cleos create account eosio eosio.stake EOS5an8bvYFHZBmiCAzAtVSiEiixbJhLY8Uy5Z7cpf3S9UoqA3bJb 78 | cleos create account eosio eosio.token EOS7JPVyejkbQHzE9Z4HwewNzGss11GB21NPkwTX2MQFmruYFqGXm 79 | cleos create account eosio eosio.vpay EOS6szGbnziz224T1JGoUUFu2LynVG72f8D3UVAS25QgwawdH983U 80 | 81 | if [ $RECOMPILE_AND_RESET_EOSIO_CONTRACTS -eq 1 ]; then 82 | # Compile the contracts manually due to an error in the build.sh script in eosio.contracts 83 | echo -e "${CYAN}-----------------------RECOMPILING CONTRACTS-----------------------${NC}" 84 | cd "${EOSIO_CONTRACTS_ROOT}/eosio.token" 85 | eosio-cpp -I ./include -o ./eosio.token.wasm ./src/eosio.token.cpp --abigen 86 | cd "${EOSIO_CONTRACTS_ROOT}/eosio.msig" 87 | eosio-cpp -I ./include -o ./eosio.msig.wasm ./src/eosio.msig.cpp --abigen 88 | cd "${EOSIO_CONTRACTS_ROOT}/eosio.system" 89 | eosio-cpp -I ./include -I "${EOSIO_CONTRACTS_ROOT}/eosio.token/include" -o ./eosio.system.wasm ./src/eosio.system.cpp --abigen 90 | cd "${EOSIO_CONTRACTS_ROOT}/eosio.wrap" 91 | eosio-cpp -I ./include -o ./eosio.wrap.wasm ./src/eosio.wrap.cpp --abigen 92 | fi 93 | 94 | # Bootstrap new system contracts 95 | echo -e "${CYAN}-----------------------SYSTEM CONTRACTS-----------------------${NC}" 96 | cleos set contract eosio.token $EOSIO_CONTRACTS_ROOT/eosio.token/ 97 | cleos set contract eosio.msig $EOSIO_CONTRACTS_ROOT/eosio.msig/ 98 | cleos push action eosio.token create '[ "eosio", "10000000000.0000 EOS" ]' -p eosio.token 99 | echo -e " EOS TOKEN CREATED" 100 | cleos push action eosio.token issue '[ "eosio", "1000000000.0000 EOS", "memo" ]' -p eosio 101 | echo -e " EOS TOKEN ISSUED" 102 | cleos set contract eosio $EOSIO_CONTRACTS_ROOT/eosio.system/ 103 | echo -e " SYSTEM SET" 104 | cleos push action eosio setpriv '["eosio.msig", 1]' -p eosio@active 105 | cleos push action eosio init '[0, "4,EOS"]' -p eosio@active 106 | 107 | # Import user keys 108 | echo -e "${CYAN}-----------------------USER KEYS-----------------------${NC}" 109 | cleos wallet import --private-key 5JVvgRBGKXSzLYMHgyMFH5AHjDzrMbyEPRdj8J6EVrXJs8adFpK 110 | cleos wallet import --private-key 5KBhzoszXcrphWPsuyTxoKJTtMMcPhQYwfivXxma8dDeaLG7Hsq 111 | cleos wallet import --private-key 5J9UYL9VcDfykAB7mcx9nFfRKki5djG9AXGV6DJ8d5XPYDJDyUy 112 | cleos wallet import --private-key 5HtnwWCbMpR1ATYoXY4xb1E4HAU9mzGvDrawyK5May68cYrJR7r 113 | cleos wallet import --private-key 5Jjx6z5SJ7WhVU2bgG2si6Y1up1JTXHj7qhC9kKUXPXb1K1Xnj6 # dcbtestusera 114 | cleos wallet import --private-key 5HyQUNxE9T83RLiS9HdZeJck5WRqNSSzVztZ3JwYvkYPrG8Ca1U # dcbtestuserb 115 | cleos wallet import --private-key 5KZC9soBHR4AF1kt93pCNfjSLPJN9y51AKR4r4vvPsiPvFdLG3t # dcbtestuserc 116 | cleos wallet import --private-key 5K9dtgQXBCggrMugEAxsBfcUZ8mmnbDpiZZYt7RvoxwChqiFdS1 # dcbtestuserd 117 | cleos wallet import --private-key 5JU8qQMV3cD4HzA14meGEBWwWxNWAk9QAebSkQotv4wXHkKncNh # dcbtestusere 118 | cleos wallet import --private-key 5K8juhLvjpPHDX1VkueBYKi2EeUVWMHACed9HF39pp6ussah3ig # bank.pay2key 119 | cleos wallet import --private-key 5Js2o8RLjC3PcsEEEdprpgNEg4ZfjUQdiL2FHheWFFKgb4QSMX9 # everipediaiq 120 | cleos wallet import --private-key 5JmBnFBTBHAuhgX7iAxNnb5SEUpyBiYqNrh789XWBujN6iXU8dG # frax.reserve 121 | cleos wallet import --private-key 5Jka9J9sthYAGHAJYJEYVuZSSnuTgpqV5WMaMMxow5MRqDUWRGt # tethertether 122 | cleos wallet import --private-key 5Jn4z4UhDh68GZREnDpBtMXPAx96d3CX7mLgSbUTca4eEUZNxho # fraxtokenfxs 123 | cleos wallet import --private-key 5HpMNASust7Negki66DJ5benpQAsXBRM3jDpHe8eREddYctA5mF # frax.loans 124 | 125 | # Create user accounts 126 | echo -e "${CYAN}-----------------------USER ACCOUNTS-----------------------${NC}" 127 | cleos system newaccount eosio bank.shares EOS6XeRbyHP1wkfEvFeHJNccr4NA9QhnAr6cU21Kaar32Y5aHM5FP --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 128 | cleos system newaccount eosio bank.price EOS8dYVzNktdam3Vn31mSXcmbj7J7MzGNudqKb3MLW1wdxWJpEbrw --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 129 | cleos system newaccount eosio bank.safesnd EOS68s2PrHPDeGWTKczrNZCn4MDMgoW6SFHuTQhXYUNLT1hAmJei8 --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 130 | cleos system newaccount eosio bank.pay2key EOS65yGjjyeyduJMGpQMGy39NcJenXFQ52HgroYos4dwjbwxu5TTW --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 131 | cleos system newaccount eosio frax.reserve EOS6jA39vSMGVHVQzxhYhE9gMToCYG9U9QLZiWZschCgfQuKJ6nrF --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 132 | cleos system newaccount eosio frax.loans EOS6DcmhfH9RSEftsRa6k8uH7E76sLRtj3hFPyVRLoNDEBdZE1anc --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 133 | cleos system newaccount eosio tethertether EOS6RAcCwqUBjPzJrN5vYBF7JLDrcEQEWnD5mnr1NSvYaEuJ5DUZK --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 134 | cleos system newaccount eosio everipediaiq EOS5Fpz9W4xkBGrvAAm3FERwcBTGzafeQkAzY6CeAEaxX3CedPL4N --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 135 | cleos system newaccount eosio dcbtestusera EOS7LpZDPKwWWXgJnNYnX6LCBgNqCEqugW9oUQr7XqcSfz7aSFk8o --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 136 | cleos system newaccount eosio dcbtestuserb EOS6KnJPV1mDuS8pYuLucaWzkwbWjGPeJsfQDpqc7NZ4F7zTQh4Wt --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 137 | cleos system newaccount eosio dcbtestuserc EOS76Pcyw1Hd7hW8hkZdUE1DQ3UiRtjmAKQ3muKwidRqmaM8iNtDy --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 138 | cleos system newaccount eosio dcbtestuserd EOS7jnmGEK9i33y3N1aV29AYrFptyJ43L7pATBEuVq4fVXG1hzs3G --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 139 | cleos system newaccount eosio dcbtestusere EOS7vr4QpGP7ixUSeumeEahHQ99YDE5jiBucf1B2zhuidHzeni1dD --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 140 | cleos system newaccount eosio fraxtokenfxs EOS7vr4QpGP7ixUSeumeEahHQ99YDE5jiBucf1B2zhuidHzeni1dD --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 141 | 142 | # Deploy eosio.wrap 143 | echo -e "${CYAN}-----------------------EOSIO WRAP-----------------------${NC}" 144 | cleos wallet import --private-key 5J3JRDhf4JNhzzjEZAsQEgtVuqvsPPdZv4Tm6SjMRx1ZqToaray 145 | cleos system newaccount eosio eosio.wrap EOS7LpGN1Qz5AbCJmsHzhG7sWEGd9mwhTXWmrYXqxhTknY2fvHQ1A --stake-cpu "50 EOS" --stake-net "10 EOS" --buy-ram-kbytes 5000 --transfer 146 | cleos push action eosio setpriv '["eosio.wrap", 1]' -p eosio@active 147 | cleos set contract eosio.wrap $EOSIO_CONTRACTS_ROOT/eosio.wrap/ 148 | 149 | 150 | # Transfer EOS to testing accounts 151 | echo -e "${CYAN}-----------------------TRANSFERRING EOS-----------------------${NC}" 152 | cleos transfer eosio dcbtestusera "1000 EOS" 153 | cleos transfer eosio dcbtestuserb "1000 EOS" 154 | cleos transfer eosio dcbtestuserc "1000 EOS" 155 | cleos transfer eosio dcbtestuserd "1000 EOS" 156 | cleos transfer eosio dcbtestusere "1000 EOS" 157 | 158 | ## Deploy contracts 159 | echo -e "${CYAN}-----------------------DEPLOYING CONTRACTS-----------------------${NC}" 160 | cleos set contract bank.shares ../bank.shares/ 161 | cleos set contract bank.price ../bank.price/ 162 | cleos set contract bank.safesnd ../bank.safesnd/ 163 | cleos set contract bank.cdp ../bank.cdp/ 164 | cleos set contract bank.pay2key ../bank.pay2key/ 165 | cleos set contract everipediaiq $EOSIO_CONTRACTS_ROOT/eosio.token/ 166 | cleos set contract tethertether $EOSIO_CONTRACTS_ROOT/eosio.token/ 167 | cleos set contract fraxtokenfxs $EOSIO_CONTRACTS_ROOT/eosio.token/ 168 | 169 | echo -e "${CYAN}-----------------------TRANSFERRING IQ-----------------------${NC}" 170 | cleos push action everipediaiq create '[ "everipediaiq", "10000000000.000 IQ" ]' -p everipediaiq 171 | cleos push action everipediaiq issue '[ "everipediaiq", "1000000000.000 IQ", "issue IQ" ]' -p everipediaiq 172 | cleos push action everipediaiq transfer '["everipediaiq", "dcbtestusera", "10000.000 IQ", "memo"]' -p everipediaiq 173 | cleos push action everipediaiq transfer '["everipediaiq", "dcbtestuserb", "10000.000 IQ", "memo"]' -p everipediaiq 174 | cleos push action everipediaiq transfer '["everipediaiq", "dcbtestuserc", "10000.000 IQ", "memo"]' -p everipediaiq 175 | cleos push action everipediaiq transfer '["everipediaiq", "dcbtestuserd", "10000.000 IQ", "memo"]' -p everipediaiq 176 | cleos push action everipediaiq transfer '["everipediaiq", "dcbtestusere", "10000.000 IQ", "memo"]' -p everipediaiq 177 | 178 | echo -e "${CYAN}-----------------------TRANSFERRING TETHER-----------------------${NC}" 179 | cleos push action tethertether create '[ "tethertether", "10000000000.0000 USDT" ]' -p tethertether 180 | cleos push action tethertether issue '[ "tethertether", "1000000000.0000 USDT", "issue USDT" ]' -p tethertether 181 | cleos push action tethertether transfer '["tethertether", "dcbtestusera", "10000.0000 USDT", "memo"]' -p tethertether 182 | cleos push action tethertether transfer '["tethertether", "dcbtestuserb", "10000.0000 USDT", "memo"]' -p tethertether 183 | cleos push action tethertether transfer '["tethertether", "dcbtestuserc", "10000.0000 USDT", "memo"]' -p tethertether 184 | cleos push action tethertether transfer '["tethertether", "dcbtestuserd", "10000.0000 USDT", "memo"]' -p tethertether 185 | cleos push action tethertether transfer '["tethertether", "dcbtestusere", "10000.0000 USDT", "memo"]' -p tethertether 186 | 187 | echo -e "${CYAN}-----------------------TRANSFERRING FRAX-----------------------${NC}" 188 | cleos push action fraxtokenfxs create '[ "frax.reserve", "10000000000.0000 FRAX" ]' -p fraxtokenfxs 189 | 190 | echo -e "${CYAN}-----------------------TRANSFERRING FXS-----------------------${NC}" 191 | cleos push action fraxtokenfxs create '[ "fraxtokenfxs", "1000000.0000 FXS" ]' -p fraxtokenfxs # 1M cap fixed supply 192 | cleos push action fraxtokenfxs issue '[ "fraxtokenfxs", "1000000.0000 FXS", "issue FXS" ]' -p fraxtokenfxs 193 | cleos push action fraxtokenfxs transfer '["fraxtokenfxs", "dcbtestusera", "10000.0000 FXS", "memo"]' -p fraxtokenfxs 194 | cleos push action fraxtokenfxs transfer '["fraxtokenfxs", "dcbtestuserb", "10000.0000 FXS", "memo"]' -p fraxtokenfxs 195 | cleos push action fraxtokenfxs transfer '["fraxtokenfxs", "dcbtestuserc", "10000.0000 FXS", "memo"]' -p fraxtokenfxs 196 | cleos push action fraxtokenfxs transfer '["fraxtokenfxs", "dcbtestuserd", "10000.0000 FXS", "memo"]' -p fraxtokenfxs 197 | cleos push action fraxtokenfxs transfer '["fraxtokenfxs", "dcbtestusere", "10000.0000 FXS", "memo"]' -p fraxtokenfxs 198 | 199 | # Grant code permissions for contracts that need it 200 | cleos set account permission bank.safesnd active '{ "threshold": 1, "keys": [{ "key": "EOS68s2PrHPDeGWTKczrNZCn4MDMgoW6SFHuTQhXYUNLT1hAmJei8", "weight": 1 }], "accounts": [{ "permission": { "actor":"bank.safesnd","permission":"eosio.code" }, "weight":1 }] }' owner -p bank.safesnd 201 | cleos set account permission bank.pay2key active '{ "threshold": 1, "keys": [{ "key": "EOS65yGjjyeyduJMGpQMGy39NcJenXFQ52HgroYos4dwjbwxu5TTW", "weight": 1 }], "accounts": [{ "permission": { "actor":"bank.pay2key","permission":"eosio.code" }, "weight":1 } ] }' 202 | cleos set account permission frax.reserve active '{ "threshold": 1, "keys": [{ "key": "EOS6jA39vSMGVHVQzxhYhE9gMToCYG9U9QLZiWZschCgfQuKJ6nrF", "weight": 1 }], "accounts": [{ "permission": { "actor":"frax.reserve","permission":"eosio.code" }, "weight":1 } ] }' 203 | cleos set account permission frax.loans active '{ "threshold": 1, "keys": [{ "key": "EOS6DcmhfH9RSEftsRa6k8uH7E76sLRtj3hFPyVRLoNDEBdZE1anc", "weight": 1 }], "accounts": [{ "permission": { "actor":"frax.loans","permission":"eosio.code" }, "weight":1 } ] }' 204 | 205 | echo -e "${CYAN}-----------------------COMPLETE-----------------------${NC}" 206 | -------------------------------------------------------------------------------- /bank.pay2key/relay-server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "relay-server", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@hapi/address": { 8 | "version": "2.0.0", 9 | "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.0.0.tgz", 10 | "integrity": "sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==" 11 | }, 12 | "@hapi/hoek": { 13 | "version": "6.2.1", 14 | "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-6.2.1.tgz", 15 | "integrity": "sha512-+ryw4GU9pjr1uT6lBuErHJg3NYqzwJTvZ75nKuJijEzpd00Uqi6oiawTGDDf5Hl0zWmI7qHfOtaqB0kpQZJQzA==" 16 | }, 17 | "@hapi/joi": { 18 | "version": "15.0.0", 19 | "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.0.0.tgz", 20 | "integrity": "sha512-pLCfcSeT26g59jEKZntmzlqe19dRMDNxCFKGD4CriF8+9FAD3Mq1aWNuKIFpKpX+u3x8lxLKXolDwk0gYl3b2w==", 21 | "requires": { 22 | "@hapi/address": "2.x.x", 23 | "@hapi/hoek": "6.x.x", 24 | "@hapi/topo": "3.x.x" 25 | } 26 | }, 27 | "@hapi/topo": { 28 | "version": "3.1.0", 29 | "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.0.tgz", 30 | "integrity": "sha512-gZDI/eXOIk8kP2PkUKjWu9RW8GGVd2Hkgjxyr/S7Z+JF+0mr7bAlbw+DkTRxnD580o8Kqxlnba9wvqp5aOHBww==", 31 | "requires": { 32 | "@hapi/hoek": "6.x.x" 33 | } 34 | }, 35 | "accepts": { 36 | "version": "1.3.6", 37 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.6.tgz", 38 | "integrity": "sha512-QsaoUD2dpVpjENy8JFpQnXP9vyzoZPmAoKrE3S6HtSB7qzSebkJNnmdY4p004FQUSSiHXPueENpoeuUW/7a8Ig==", 39 | "requires": { 40 | "mime-types": "~2.1.24", 41 | "negotiator": "0.6.1" 42 | } 43 | }, 44 | "array-flatten": { 45 | "version": "1.1.1", 46 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 47 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 48 | }, 49 | "babel-runtime": { 50 | "version": "6.26.0", 51 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 52 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 53 | "requires": { 54 | "core-js": "^2.4.0", 55 | "regenerator-runtime": "^0.11.0" 56 | } 57 | }, 58 | "base-x": { 59 | "version": "3.0.5", 60 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz", 61 | "integrity": "sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==", 62 | "requires": { 63 | "safe-buffer": "^5.0.1" 64 | } 65 | }, 66 | "basic-auth": { 67 | "version": "2.0.1", 68 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", 69 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", 70 | "requires": { 71 | "safe-buffer": "5.1.2" 72 | } 73 | }, 74 | "bigi": { 75 | "version": "1.4.2", 76 | "resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", 77 | "integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU=" 78 | }, 79 | "body-parser": { 80 | "version": "1.19.0", 81 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 82 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 83 | "requires": { 84 | "bytes": "3.1.0", 85 | "content-type": "~1.0.4", 86 | "debug": "2.6.9", 87 | "depd": "~1.1.2", 88 | "http-errors": "1.7.2", 89 | "iconv-lite": "0.4.24", 90 | "on-finished": "~2.3.0", 91 | "qs": "6.7.0", 92 | "raw-body": "2.4.0", 93 | "type-is": "~1.6.17" 94 | } 95 | }, 96 | "browserify-aes": { 97 | "version": "1.2.0", 98 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 99 | "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", 100 | "requires": { 101 | "buffer-xor": "^1.0.3", 102 | "cipher-base": "^1.0.0", 103 | "create-hash": "^1.1.0", 104 | "evp_bytestokey": "^1.0.3", 105 | "inherits": "^2.0.1", 106 | "safe-buffer": "^5.0.1" 107 | } 108 | }, 109 | "bs58": { 110 | "version": "4.0.1", 111 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 112 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 113 | "requires": { 114 | "base-x": "^3.0.2" 115 | } 116 | }, 117 | "buffer-xor": { 118 | "version": "1.0.3", 119 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 120 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" 121 | }, 122 | "bytebuffer": { 123 | "version": "5.0.1", 124 | "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", 125 | "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", 126 | "requires": { 127 | "long": "~3" 128 | } 129 | }, 130 | "bytes": { 131 | "version": "3.1.0", 132 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 133 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 134 | }, 135 | "cipher-base": { 136 | "version": "1.0.4", 137 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 138 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", 139 | "requires": { 140 | "inherits": "^2.0.1", 141 | "safe-buffer": "^5.0.1" 142 | } 143 | }, 144 | "content-disposition": { 145 | "version": "0.5.2", 146 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 147 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 148 | }, 149 | "content-type": { 150 | "version": "1.0.4", 151 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 152 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 153 | }, 154 | "cookie": { 155 | "version": "0.3.1", 156 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 157 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 158 | }, 159 | "cookie-signature": { 160 | "version": "1.0.6", 161 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 162 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 163 | }, 164 | "core-js": { 165 | "version": "2.6.5", 166 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", 167 | "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==" 168 | }, 169 | "create-hash": { 170 | "version": "1.2.0", 171 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 172 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 173 | "requires": { 174 | "cipher-base": "^1.0.1", 175 | "inherits": "^2.0.1", 176 | "md5.js": "^1.3.4", 177 | "ripemd160": "^2.0.1", 178 | "sha.js": "^2.4.0" 179 | } 180 | }, 181 | "create-hmac": { 182 | "version": "1.1.7", 183 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 184 | "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", 185 | "requires": { 186 | "cipher-base": "^1.0.3", 187 | "create-hash": "^1.1.0", 188 | "inherits": "^2.0.1", 189 | "ripemd160": "^2.0.0", 190 | "safe-buffer": "^5.0.1", 191 | "sha.js": "^2.4.8" 192 | } 193 | }, 194 | "debug": { 195 | "version": "2.6.9", 196 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 197 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 198 | "requires": { 199 | "ms": "2.0.0" 200 | } 201 | }, 202 | "depd": { 203 | "version": "1.1.2", 204 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 205 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 206 | }, 207 | "destroy": { 208 | "version": "1.0.4", 209 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 210 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 211 | }, 212 | "dotenv": { 213 | "version": "7.0.0", 214 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", 215 | "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==" 216 | }, 217 | "ecurve": { 218 | "version": "1.0.6", 219 | "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", 220 | "integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==", 221 | "requires": { 222 | "bigi": "^1.1.0", 223 | "safe-buffer": "^5.0.1" 224 | } 225 | }, 226 | "ee-first": { 227 | "version": "1.1.1", 228 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 229 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 230 | }, 231 | "encodeurl": { 232 | "version": "1.0.2", 233 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 234 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 235 | }, 236 | "eosjs": { 237 | "version": "20.0.0", 238 | "resolved": "https://registry.npmjs.org/eosjs/-/eosjs-20.0.0.tgz", 239 | "integrity": "sha512-Ak9CPtZgCFayUmq43X3Nsn4v67lkLfSzEdTUfMk1XAWA5s4HRn7lBTeTeDCzJ/rggi+dZ170VeJwc5T3gPk4HQ==", 240 | "requires": { 241 | "babel-runtime": "6.26.0", 242 | "eosjs-ecc": "4.0.4", 243 | "text-encoding": "0.7.0" 244 | } 245 | }, 246 | "eosjs-ecc": { 247 | "version": "4.0.4", 248 | "resolved": "https://registry.npmjs.org/eosjs-ecc/-/eosjs-ecc-4.0.4.tgz", 249 | "integrity": "sha512-9wAYefts4TidHOu+eN9nAisZdWpUzlUimZrB63oP7+/s4xRNJEn2Vvep2ICRODpxpidbshM1L7WaSYW9oiV5gA==", 250 | "requires": { 251 | "bigi": "^1.4.2", 252 | "browserify-aes": "^1.0.6", 253 | "bs58": "^4.0.1", 254 | "bytebuffer": "^5.0.1", 255 | "create-hash": "^1.1.3", 256 | "create-hmac": "^1.1.6", 257 | "ecurve": "^1.0.5", 258 | "randombytes": "^2.0.5" 259 | } 260 | }, 261 | "escape-html": { 262 | "version": "1.0.3", 263 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 264 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 265 | }, 266 | "etag": { 267 | "version": "1.8.1", 268 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 269 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 270 | }, 271 | "evp_bytestokey": { 272 | "version": "1.0.3", 273 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 274 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", 275 | "requires": { 276 | "md5.js": "^1.3.4", 277 | "safe-buffer": "^5.1.1" 278 | } 279 | }, 280 | "express": { 281 | "version": "4.16.4", 282 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", 283 | "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", 284 | "requires": { 285 | "accepts": "~1.3.5", 286 | "array-flatten": "1.1.1", 287 | "body-parser": "1.18.3", 288 | "content-disposition": "0.5.2", 289 | "content-type": "~1.0.4", 290 | "cookie": "0.3.1", 291 | "cookie-signature": "1.0.6", 292 | "debug": "2.6.9", 293 | "depd": "~1.1.2", 294 | "encodeurl": "~1.0.2", 295 | "escape-html": "~1.0.3", 296 | "etag": "~1.8.1", 297 | "finalhandler": "1.1.1", 298 | "fresh": "0.5.2", 299 | "merge-descriptors": "1.0.1", 300 | "methods": "~1.1.2", 301 | "on-finished": "~2.3.0", 302 | "parseurl": "~1.3.2", 303 | "path-to-regexp": "0.1.7", 304 | "proxy-addr": "~2.0.4", 305 | "qs": "6.5.2", 306 | "range-parser": "~1.2.0", 307 | "safe-buffer": "5.1.2", 308 | "send": "0.16.2", 309 | "serve-static": "1.13.2", 310 | "setprototypeof": "1.1.0", 311 | "statuses": "~1.4.0", 312 | "type-is": "~1.6.16", 313 | "utils-merge": "1.0.1", 314 | "vary": "~1.1.2" 315 | }, 316 | "dependencies": { 317 | "body-parser": { 318 | "version": "1.18.3", 319 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 320 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 321 | "requires": { 322 | "bytes": "3.0.0", 323 | "content-type": "~1.0.4", 324 | "debug": "2.6.9", 325 | "depd": "~1.1.2", 326 | "http-errors": "~1.6.3", 327 | "iconv-lite": "0.4.23", 328 | "on-finished": "~2.3.0", 329 | "qs": "6.5.2", 330 | "raw-body": "2.3.3", 331 | "type-is": "~1.6.16" 332 | } 333 | }, 334 | "bytes": { 335 | "version": "3.0.0", 336 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 337 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 338 | }, 339 | "http-errors": { 340 | "version": "1.6.3", 341 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 342 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 343 | "requires": { 344 | "depd": "~1.1.2", 345 | "inherits": "2.0.3", 346 | "setprototypeof": "1.1.0", 347 | "statuses": ">= 1.4.0 < 2" 348 | } 349 | }, 350 | "iconv-lite": { 351 | "version": "0.4.23", 352 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 353 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 354 | "requires": { 355 | "safer-buffer": ">= 2.1.2 < 3" 356 | } 357 | }, 358 | "qs": { 359 | "version": "6.5.2", 360 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 361 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 362 | }, 363 | "raw-body": { 364 | "version": "2.3.3", 365 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 366 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 367 | "requires": { 368 | "bytes": "3.0.0", 369 | "http-errors": "1.6.3", 370 | "iconv-lite": "0.4.23", 371 | "unpipe": "1.0.0" 372 | } 373 | }, 374 | "setprototypeof": { 375 | "version": "1.1.0", 376 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 377 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 378 | }, 379 | "statuses": { 380 | "version": "1.4.0", 381 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 382 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 383 | } 384 | } 385 | }, 386 | "finalhandler": { 387 | "version": "1.1.1", 388 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 389 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 390 | "requires": { 391 | "debug": "2.6.9", 392 | "encodeurl": "~1.0.2", 393 | "escape-html": "~1.0.3", 394 | "on-finished": "~2.3.0", 395 | "parseurl": "~1.3.2", 396 | "statuses": "~1.4.0", 397 | "unpipe": "~1.0.0" 398 | }, 399 | "dependencies": { 400 | "statuses": { 401 | "version": "1.4.0", 402 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 403 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 404 | } 405 | } 406 | }, 407 | "forwarded": { 408 | "version": "0.1.2", 409 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 410 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 411 | }, 412 | "fresh": { 413 | "version": "0.5.2", 414 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 415 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 416 | }, 417 | "hash-base": { 418 | "version": "3.0.4", 419 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", 420 | "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", 421 | "requires": { 422 | "inherits": "^2.0.1", 423 | "safe-buffer": "^5.0.1" 424 | } 425 | }, 426 | "http-errors": { 427 | "version": "1.7.2", 428 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 429 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 430 | "requires": { 431 | "depd": "~1.1.2", 432 | "inherits": "2.0.3", 433 | "setprototypeof": "1.1.1", 434 | "statuses": ">= 1.5.0 < 2", 435 | "toidentifier": "1.0.0" 436 | } 437 | }, 438 | "iconv-lite": { 439 | "version": "0.4.24", 440 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 441 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 442 | "requires": { 443 | "safer-buffer": ">= 2.1.2 < 3" 444 | } 445 | }, 446 | "inherits": { 447 | "version": "2.0.3", 448 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 449 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 450 | }, 451 | "ipaddr.js": { 452 | "version": "1.9.0", 453 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", 454 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" 455 | }, 456 | "long": { 457 | "version": "3.2.0", 458 | "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", 459 | "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" 460 | }, 461 | "md5.js": { 462 | "version": "1.3.5", 463 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", 464 | "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", 465 | "requires": { 466 | "hash-base": "^3.0.0", 467 | "inherits": "^2.0.1", 468 | "safe-buffer": "^5.1.2" 469 | } 470 | }, 471 | "media-typer": { 472 | "version": "0.3.0", 473 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 474 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 475 | }, 476 | "merge-descriptors": { 477 | "version": "1.0.1", 478 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 479 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 480 | }, 481 | "methods": { 482 | "version": "1.1.2", 483 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 484 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 485 | }, 486 | "mime": { 487 | "version": "1.4.1", 488 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 489 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 490 | }, 491 | "mime-db": { 492 | "version": "1.40.0", 493 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 494 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 495 | }, 496 | "mime-types": { 497 | "version": "2.1.24", 498 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 499 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 500 | "requires": { 501 | "mime-db": "1.40.0" 502 | } 503 | }, 504 | "morgan": { 505 | "version": "1.9.1", 506 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", 507 | "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", 508 | "requires": { 509 | "basic-auth": "~2.0.0", 510 | "debug": "2.6.9", 511 | "depd": "~1.1.2", 512 | "on-finished": "~2.3.0", 513 | "on-headers": "~1.0.1" 514 | } 515 | }, 516 | "ms": { 517 | "version": "2.0.0", 518 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 519 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 520 | }, 521 | "negotiator": { 522 | "version": "0.6.1", 523 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 524 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 525 | }, 526 | "node-fetch": { 527 | "version": "2.4.1", 528 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.4.1.tgz", 529 | "integrity": "sha512-P9UbpFK87NyqBZzUuDBDz4f6Yiys8xm8j7ACDbi6usvFm6KItklQUKjeoqTrYS/S1k6I8oaOC2YLLDr/gg26Mw==" 530 | }, 531 | "on-finished": { 532 | "version": "2.3.0", 533 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 534 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 535 | "requires": { 536 | "ee-first": "1.1.1" 537 | } 538 | }, 539 | "on-headers": { 540 | "version": "1.0.2", 541 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", 542 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" 543 | }, 544 | "parseurl": { 545 | "version": "1.3.3", 546 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 547 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 548 | }, 549 | "path-to-regexp": { 550 | "version": "0.1.7", 551 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 552 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 553 | }, 554 | "proxy-addr": { 555 | "version": "2.0.5", 556 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", 557 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", 558 | "requires": { 559 | "forwarded": "~0.1.2", 560 | "ipaddr.js": "1.9.0" 561 | } 562 | }, 563 | "qs": { 564 | "version": "6.7.0", 565 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 566 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 567 | }, 568 | "randombytes": { 569 | "version": "2.1.0", 570 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 571 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 572 | "requires": { 573 | "safe-buffer": "^5.1.0" 574 | } 575 | }, 576 | "range-parser": { 577 | "version": "1.2.0", 578 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 579 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 580 | }, 581 | "raw-body": { 582 | "version": "2.4.0", 583 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 584 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 585 | "requires": { 586 | "bytes": "3.1.0", 587 | "http-errors": "1.7.2", 588 | "iconv-lite": "0.4.24", 589 | "unpipe": "1.0.0" 590 | } 591 | }, 592 | "regenerator-runtime": { 593 | "version": "0.11.1", 594 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 595 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" 596 | }, 597 | "ripemd160": { 598 | "version": "2.0.2", 599 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 600 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 601 | "requires": { 602 | "hash-base": "^3.0.0", 603 | "inherits": "^2.0.1" 604 | } 605 | }, 606 | "safe-buffer": { 607 | "version": "5.1.2", 608 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 609 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 610 | }, 611 | "safer-buffer": { 612 | "version": "2.1.2", 613 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 614 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 615 | }, 616 | "send": { 617 | "version": "0.16.2", 618 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 619 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 620 | "requires": { 621 | "debug": "2.6.9", 622 | "depd": "~1.1.2", 623 | "destroy": "~1.0.4", 624 | "encodeurl": "~1.0.2", 625 | "escape-html": "~1.0.3", 626 | "etag": "~1.8.1", 627 | "fresh": "0.5.2", 628 | "http-errors": "~1.6.2", 629 | "mime": "1.4.1", 630 | "ms": "2.0.0", 631 | "on-finished": "~2.3.0", 632 | "range-parser": "~1.2.0", 633 | "statuses": "~1.4.0" 634 | }, 635 | "dependencies": { 636 | "http-errors": { 637 | "version": "1.6.3", 638 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 639 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 640 | "requires": { 641 | "depd": "~1.1.2", 642 | "inherits": "2.0.3", 643 | "setprototypeof": "1.1.0", 644 | "statuses": ">= 1.4.0 < 2" 645 | } 646 | }, 647 | "setprototypeof": { 648 | "version": "1.1.0", 649 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 650 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 651 | }, 652 | "statuses": { 653 | "version": "1.4.0", 654 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 655 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 656 | } 657 | } 658 | }, 659 | "serve-static": { 660 | "version": "1.13.2", 661 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 662 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 663 | "requires": { 664 | "encodeurl": "~1.0.2", 665 | "escape-html": "~1.0.3", 666 | "parseurl": "~1.3.2", 667 | "send": "0.16.2" 668 | } 669 | }, 670 | "setprototypeof": { 671 | "version": "1.1.1", 672 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 673 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 674 | }, 675 | "sha.js": { 676 | "version": "2.4.11", 677 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 678 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 679 | "requires": { 680 | "inherits": "^2.0.1", 681 | "safe-buffer": "^5.0.1" 682 | } 683 | }, 684 | "statuses": { 685 | "version": "1.5.0", 686 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 687 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 688 | }, 689 | "text-encoding": { 690 | "version": "0.7.0", 691 | "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz", 692 | "integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==" 693 | }, 694 | "toidentifier": { 695 | "version": "1.0.0", 696 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 697 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 698 | }, 699 | "type-is": { 700 | "version": "1.6.18", 701 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 702 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 703 | "requires": { 704 | "media-typer": "0.3.0", 705 | "mime-types": "~2.1.24" 706 | } 707 | }, 708 | "unpipe": { 709 | "version": "1.0.0", 710 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 711 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 712 | }, 713 | "utils-merge": { 714 | "version": "1.0.1", 715 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 716 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 717 | }, 718 | "vary": { 719 | "version": "1.1.2", 720 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 721 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 722 | } 723 | } 724 | } 725 | --------------------------------------------------------------------------------