mirror of
https://github.com/Instadapp/smart-contract.git
synced 2024-07-29 22:08:07 +00:00
Smart contract initial setup
This commit is contained in:
parent
a82ac41f6f
commit
1994d5ce31
3
.babelrc
Normal file
3
.babelrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"presets": ["env","es2015", "stage-2", "stage-3"]
|
||||||
|
}
|
37
.circleci/config.yml
Normal file
37
.circleci/config.yml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Javascript Node CircleCI 2.0 configuration file
|
||||||
|
#
|
||||||
|
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
|
||||||
|
#
|
||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
docker:
|
||||||
|
# specify the version you desire here
|
||||||
|
- image: circleci/node:8.4.0
|
||||||
|
|
||||||
|
# Specify service dependencies here if necessary
|
||||||
|
# CircleCI maintains a library of pre-built images
|
||||||
|
# documented at https://circleci.com/docs/2.0/circleci-images/
|
||||||
|
# - image: circleci/mongo:3.4.4
|
||||||
|
|
||||||
|
working_directory: ~/repo
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
# Download and cache dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- v1-dependencies-{{ checksum "package.json" }}
|
||||||
|
# fallback to using the latest cache if no exact match is found
|
||||||
|
- v1-dependencies-
|
||||||
|
|
||||||
|
- run: npm install
|
||||||
|
|
||||||
|
- save_cache:
|
||||||
|
paths:
|
||||||
|
- node_modules
|
||||||
|
key: v1-dependencies-{{ checksum "package.json" }}
|
||||||
|
|
||||||
|
# run tests!
|
||||||
|
- run: npm run test-ci
|
2
.env.sample
Normal file
2
.env.sample
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
RINKEBY_PRIVATE_KEY="df7ebe6c9601adf4e911faac9da547686e6453a11cf13264d895fc2979a6bec2"
|
||||||
|
ROPSTEN_PRIVATE_KEY="192f175c2f5e5a9437fdbc12043404763f96ccbcd6fc32b1d61dbb61e14e6f34"
|
4
.eslintignore
Normal file
4
.eslintignore
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
tmp/**
|
||||||
|
build/**
|
||||||
|
node_modules/**
|
||||||
|
contracts/**
|
102
.eslintrc.js
Normal file
102
.eslintrc.js
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
module.exports = {
|
||||||
|
parser: 'babel-eslint',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaFeatures: {
|
||||||
|
generators: true,
|
||||||
|
experimentalObjectRestSpread: true
|
||||||
|
},
|
||||||
|
sourceType: 'module',
|
||||||
|
allowImportExportEverywhere: false
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:import/errors',
|
||||||
|
'plugin:import/warnings',
|
||||||
|
'plugin:promise/recommended',
|
||||||
|
'plugin:security/recommended'
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
'compat',
|
||||||
|
'prettier',
|
||||||
|
'promise',
|
||||||
|
'security'
|
||||||
|
],
|
||||||
|
settings: {
|
||||||
|
'import/resolver': {
|
||||||
|
node: {
|
||||||
|
extensions: ['.js', '.jsx', '.json', '.css'],
|
||||||
|
paths: './src'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
polyfills: ['fetch', 'promises']
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
globals: {
|
||||||
|
__DEV__: true,
|
||||||
|
__dirname: true,
|
||||||
|
after: true,
|
||||||
|
afterAll: true,
|
||||||
|
afterEach: true,
|
||||||
|
artifacts: true,
|
||||||
|
assert: true,
|
||||||
|
before: true,
|
||||||
|
beforeAll: true,
|
||||||
|
beforeEach: true,
|
||||||
|
console: true,
|
||||||
|
contract: true,
|
||||||
|
describe: true,
|
||||||
|
expect: true,
|
||||||
|
fetch: true,
|
||||||
|
global: true,
|
||||||
|
it: true,
|
||||||
|
module: true,
|
||||||
|
process: true,
|
||||||
|
Promise: true,
|
||||||
|
require: true,
|
||||||
|
setTimeout: true,
|
||||||
|
test: true,
|
||||||
|
xdescribe: true,
|
||||||
|
xit: true,
|
||||||
|
web3: true
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'compat/compat': 'error',
|
||||||
|
'import/first': 'error',
|
||||||
|
'import/no-anonymous-default-export': 'error',
|
||||||
|
'import/no-unassigned-import': 'error',
|
||||||
|
'import/prefer-default-export': 'error',
|
||||||
|
'import/no-named-as-default': 'off',
|
||||||
|
'import/no-unresolved': 'error',
|
||||||
|
'prettier/prettier': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
semi: false,
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'none'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'promise/avoid-new': 'off',
|
||||||
|
'security/detect-object-injection': 'off',
|
||||||
|
'arrow-body-style': 'off',
|
||||||
|
'lines-between-class-members': ['error', 'always'],
|
||||||
|
'no-console': ['warn', { allow: ['assert'] }],
|
||||||
|
'no-shadow': 'error',
|
||||||
|
'no-var': 'error',
|
||||||
|
|
||||||
|
'padding-line-between-statements': [
|
||||||
|
'error',
|
||||||
|
{ blankLine: 'always', prev: 'class', next: '*' },
|
||||||
|
{ blankLine: 'always', prev: 'do', next: '*' },
|
||||||
|
{ blankLine: 'always', prev: '*', next: 'export' },
|
||||||
|
{ blankLine: 'always', prev: 'for', next: '*' },
|
||||||
|
{ blankLine: 'always', prev: 'if', next: '*' },
|
||||||
|
{ blankLine: 'always', prev: 'switch', next: '*' },
|
||||||
|
{ blankLine: 'always', prev: 'try', next: '*' },
|
||||||
|
{ blankLine: 'always', prev: 'while', next: '*' },
|
||||||
|
{ blankLine: 'always', prev: 'with', next: '*' }
|
||||||
|
],
|
||||||
|
'prefer-const': 'error'
|
||||||
|
}
|
||||||
|
}
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.sol linguist-language=Solidity
|
106
.gitignore
vendored
Normal file
106
.gitignore
vendored
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/solidity,soliditytruffle
|
||||||
|
|
||||||
|
### Solidity ###
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless
|
||||||
|
|
||||||
|
### SolidityTruffle ###
|
||||||
|
# depedencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# testing
|
||||||
|
|
||||||
|
# production
|
||||||
|
build
|
||||||
|
build_webpack
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
npm-debug.log
|
||||||
|
.truffle-solidity-loader
|
||||||
|
.vagrant/**
|
||||||
|
blockchain/geth/**
|
||||||
|
blockchain/keystore/**
|
||||||
|
blockchain/history
|
||||||
|
|
||||||
|
#truffle
|
||||||
|
.tern-port
|
||||||
|
yarn.lock
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/solidity,soliditytruffle
|
||||||
|
|
||||||
|
test-results/
|
1
.prettierignore
Normal file
1
.prettierignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package.json
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none"
|
||||||
|
}
|
6
.solcover.js
Normal file
6
.solcover.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = {
|
||||||
|
port: 9545,
|
||||||
|
testrpcOptions:
|
||||||
|
'-p 9545 -m "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat"',
|
||||||
|
copyNodeModules: false
|
||||||
|
}
|
2
.soliumignore
Normal file
2
.soliumignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
contracts/Migrations.sol
|
27
.soliumrc.json
Normal file
27
.soliumrc.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"extends": "solium:all",
|
||||||
|
"plugins": ["security"],
|
||||||
|
"rules": {
|
||||||
|
"arg-overflow": "error",
|
||||||
|
"array-declarations": "error",
|
||||||
|
"blank-lines": "error",
|
||||||
|
"camelcase": "error",
|
||||||
|
"comma-whitespace": "error",
|
||||||
|
"deprecated-suicide": "error",
|
||||||
|
"function-whitespace": "error",
|
||||||
|
"imports-on-top": "error",
|
||||||
|
"indentation": ["error", 4],
|
||||||
|
"lbrace": "error",
|
||||||
|
"mixedcase": "error",
|
||||||
|
"no-empty-blocks": "error",
|
||||||
|
"no-unused-vars": "error",
|
||||||
|
"operator-whitespace": "error",
|
||||||
|
"pragma-on-top": "error",
|
||||||
|
"quotes": ["error", "double"],
|
||||||
|
"security/no-inline-assembly": "off",
|
||||||
|
"semicolon-whitespace": "error",
|
||||||
|
"uppercase": "off",
|
||||||
|
"variable-declarations": "error",
|
||||||
|
"whitespace": "error"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
pragma solidity ^0.4.23;
|
|
||||||
|
|
||||||
|
|
||||||
contract AddressRegistry {
|
|
||||||
|
|
||||||
event AddressSet(string name, address addr);
|
|
||||||
mapping(bytes32 => address) registry;
|
|
||||||
|
|
||||||
constructor() public {
|
|
||||||
registry[keccak256(abi.encodePacked("admin"))] = msg.sender;
|
|
||||||
registry[keccak256(abi.encodePacked("owner"))] = msg.sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAddr(string memory name) public view returns(address) {
|
|
||||||
return registry[keccak256(abi.encodePacked(name))];
|
|
||||||
}
|
|
||||||
|
|
||||||
function setAddr(string memory name, address addr) public {
|
|
||||||
require(
|
|
||||||
msg.sender == getAddr("admin") ||
|
|
||||||
msg.sender == getAddr("owner"),
|
|
||||||
"Permission Denied"
|
|
||||||
);
|
|
||||||
registry[keccak256(abi.encodePacked(name))] = addr;
|
|
||||||
emit AddressSet(name, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
1
CONTRIBUTING.md
Normal file
1
CONTRIBUTING.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Contributors Guide
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Ravindra Kumar <ravidsrk@gmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
61
README.md
61
README.md
|
@ -1,2 +1,59 @@
|
||||||
# InstaProxyContract
|
# InstaDApp V2 Contracts
|
||||||
InstaDApp Proxy Contract.
|
|
||||||
|
Smart contracts comprising the business logic of the InstaDApp.
|
||||||
|
|
||||||
|
## This project uses:
|
||||||
|
- [Truffle v5](https://truffleframework.com/)
|
||||||
|
- [Ganache](https://truffleframework.com/ganache)
|
||||||
|
- [Solium](https://github.com/duaraghav8/Solium)
|
||||||
|
- [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-solidity)
|
||||||
|
- [Travis CI](https://travis-ci.org/InstaDApp/InstaContract-v2) and [Circle CI](https://circleci.com/gh/InstaDApp/InstaContract-v2)
|
||||||
|
- [Coveralls](https://coveralls.io/github/InstaDApp/InstaContract-v2?branch=master)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Install Truffle and Ganache CLI globally.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
npm install -g truffle@beta
|
||||||
|
npm install -g ganache-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create a `.env` file in the root directory and add your private key.
|
||||||
|
|
||||||
|
## Commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
Compile contracts: truffle compile
|
||||||
|
Migrate contracts: truffle migrate
|
||||||
|
Test contracts: truffle test
|
||||||
|
Run eslint: npm run lint
|
||||||
|
Run solium: npm run solium
|
||||||
|
Run solidity-coverage: npm run coverage
|
||||||
|
Run lint, solium, and truffle test: npm run test
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
```
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 InstaDApp
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
```
|
||||||
|
|
|
@ -1,43 +1,40 @@
|
||||||
pragma solidity ^0.4.23;
|
pragma solidity ^0.5.0;
|
||||||
|
|
||||||
|
|
||||||
interface AddrRegistry {
|
interface AddrRegistry {
|
||||||
function getAddr(string calldata name) external view returns(address);
|
function getAddr(string calldata) external view returns (address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
contract AddressRegistry {
|
contract AddressRegistry {
|
||||||
address public registry;
|
address public registry;
|
||||||
|
|
||||||
modifier onlyAdmin() {
|
modifier onlyAdmin() {
|
||||||
require(
|
require(msg.sender == getAddress("admin"), "Permission Denied");
|
||||||
msg.sender == getAddress("admin"),
|
|
||||||
"Permission Denied"
|
|
||||||
);
|
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAddress(string memory name) internal view returns(address) {
|
function getAddress(string memory name) internal view returns (address) {
|
||||||
AddrRegistry addrReg = AddrRegistry(registry);
|
AddrRegistry addrReg = AddrRegistry(registry);
|
||||||
return addrReg.getAddr(name);
|
return addrReg.getAddr(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract LogicRegistry is AddressRegistry {
|
|
||||||
|
|
||||||
|
contract LogicRegistry is AddressRegistry {
|
||||||
event DefaultLogicSet(address logicAddr);
|
event DefaultLogicSet(address logicAddr);
|
||||||
event LogicSet(address logicAddr, bool isLogic);
|
event LogicSet(address logicAddr, bool isLogic);
|
||||||
|
|
||||||
mapping(address => bool) public DefaultLogicProxies;
|
mapping(address => bool) public defaultLogicProxies;
|
||||||
mapping(address => bool) public LogicProxies;
|
mapping(address => bool) public logicProxies;
|
||||||
|
|
||||||
constructor(address registry_) public {
|
constructor(address registry_) public {
|
||||||
registry = registry_;
|
registry = registry_;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLogic(address logicAddr) public view returns(bool) {
|
function getLogic(address logicAddr) public view returns (bool) {
|
||||||
if (DefaultLogicProxies[logicAddr]) {
|
if (defaultLogicProxies[logicAddr]) {
|
||||||
return true;
|
return true;
|
||||||
} else if (LogicProxies[logicAddr]) {
|
} else if (logicProxies[logicAddr]) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -46,13 +43,13 @@ contract LogicRegistry is AddressRegistry {
|
||||||
|
|
||||||
function setLogic(address logicAddr, bool isLogic) public onlyAdmin {
|
function setLogic(address logicAddr, bool isLogic) public onlyAdmin {
|
||||||
require(msg.sender == getAddress("admin"), "Permission Denied");
|
require(msg.sender == getAddress("admin"), "Permission Denied");
|
||||||
LogicProxies[logicAddr] = true;
|
logicProxies[logicAddr] = true;
|
||||||
emit LogicSet(logicAddr, isLogic);
|
emit LogicSet(logicAddr, isLogic);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDefaultLogic(address logicAddr) public onlyAdmin {
|
function setDefaultLogic(address logicAddr) public onlyAdmin {
|
||||||
require(msg.sender == getAddress("admin"), "Permission Denied");
|
require(msg.sender == getAddress("admin"), "Permission Denied");
|
||||||
DefaultLogicProxies[logicAddr] = true;
|
defaultLogicProxies[logicAddr] = true;
|
||||||
emit DefaultLogicSet(logicAddr);
|
emit DefaultLogicSet(logicAddr);
|
||||||
}
|
}
|
||||||
|
|
27
contracts/Migrations.sol
Normal file
27
contracts/Migrations.sol
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
pragma solidity ^0.5.0;
|
||||||
|
|
||||||
|
/* solium-disable mixedcase */
|
||||||
|
contract Migrations {
|
||||||
|
address public owner;
|
||||||
|
uint public last_completed_migration;
|
||||||
|
|
||||||
|
modifier restricted() {
|
||||||
|
if (msg.sender == owner) _;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() public {
|
||||||
|
owner = msg.sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCompleted(uint completed) public restricted {
|
||||||
|
last_completed_migration = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgrade(address _newAddress) public restricted {
|
||||||
|
Migrations upgraded = Migrations(_newAddress);
|
||||||
|
upgraded.setCompleted(last_completed_migration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* solium-enable mixedcase */
|
||||||
|
|
39
contracts/Ownable.sol
Normal file
39
contracts/Ownable.sol
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
pragma solidity ^0.5.0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title Ownable
|
||||||
|
* @dev The Ownable contract has an owner address, and provides basic authorization control
|
||||||
|
* functions, this simplifies the implementation of "user permissions".
|
||||||
|
*/
|
||||||
|
contract Ownable {
|
||||||
|
address public owner;
|
||||||
|
|
||||||
|
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
|
||||||
|
* account.
|
||||||
|
*/
|
||||||
|
constructor() public {
|
||||||
|
owner = msg.sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Throws if called by any account other than the owner.
|
||||||
|
*/
|
||||||
|
modifier onlyOwner() {
|
||||||
|
require(msg.sender == owner, "Only owner accessible");
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Allows the current owner to transfer control of the contract to a newOwner.
|
||||||
|
* @param newOwner The address to transfer ownership to.
|
||||||
|
*/
|
||||||
|
function transferOwnership(address newOwner) public onlyOwner {
|
||||||
|
require(newOwner != address(0), "Address not equal to zero");
|
||||||
|
emit OwnershipTransferred(owner, newOwner);
|
||||||
|
owner = newOwner;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
pragma solidity ^0.4.23;
|
pragma solidity ^0.5.0;
|
||||||
|
|
||||||
|
|
||||||
interface IERC20 {
|
interface IERC20 {
|
||||||
function transfer(address to, uint256 value) external returns (bool);
|
function transfer(address to, uint256 value) external returns (bool);
|
||||||
|
@ -9,15 +8,19 @@ interface ICDP {
|
||||||
function give(bytes32 cup, address guy) external;
|
function give(bytes32 cup, address guy) external;
|
||||||
}
|
}
|
||||||
|
|
||||||
contract ProxyTest {
|
|
||||||
|
|
||||||
|
contract ProxyTest {
|
||||||
event LogTransferETH(address dest, uint amount);
|
event LogTransferETH(address dest, uint amount);
|
||||||
event LogTransferERC20(address token, address dest, uint amount);
|
event LogTransferERC20(address token, address dest, uint amount);
|
||||||
event LogTransferCDP(address dest, uint num);
|
event LogTransferCDP(address dest, uint num);
|
||||||
|
|
||||||
function transferETH(address dest, uint amount) public payable {
|
function transferETH(address dest, uint amount) public payable {
|
||||||
dest.transfer(amount);
|
dest.transfer(amount);
|
||||||
emit LogTransferETH(dest, amount);
|
|
||||||
|
emit LogTransferETH(
|
||||||
|
dest,
|
||||||
|
amount
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function transferERC20(address tokenAddr, address dest, address amount) public {
|
function transferERC20(address tokenAddr, address dest, address amount) public {
|
||||||
|
@ -31,5 +34,4 @@ contract ProxyTest {
|
||||||
loanMaster.give(bytes32(num), dest);
|
loanMaster.give(bytes32(num), dest);
|
||||||
emit LogTransferCDP(dest, num);
|
emit LogTransferCDP(dest, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
pragma solidity ^0.4.23;
|
pragma solidity ^0.5.0;
|
||||||
|
|
||||||
|
|
||||||
import "./UserProxy.sol";
|
import "./UserProxy.sol";
|
||||||
|
|
||||||
// ProxyRegistry
|
|
||||||
contract ProxyRegistry {
|
contract ProxyRegistry {
|
||||||
event Created(address indexed sender, address indexed owner, address proxy);
|
event Created(address indexed sender, address indexed owner, address proxy);
|
||||||
mapping(address => UserProxy) public proxies;
|
mapping(address => UserProxy) public proxies;
|
||||||
|
@ -26,6 +25,7 @@ contract ProxyRegistry {
|
||||||
proxies[owner] == UserProxy(0) || proxies[owner].owner() != owner,
|
proxies[owner] == UserProxy(0) || proxies[owner].owner() != owner,
|
||||||
"multiple-proxy-per-user-not-allowed"
|
"multiple-proxy-per-user-not-allowed"
|
||||||
); // Not allow new proxy if the user already has one and remains being the owner
|
); // Not allow new proxy if the user already has one and remains being the owner
|
||||||
|
|
||||||
proxy = new UserProxy(logicProxyAddr, activeDays);
|
proxy = new UserProxy(logicProxyAddr, activeDays);
|
||||||
emit Created(msg.sender, owner, address(proxy));
|
emit Created(msg.sender, owner, address(proxy));
|
||||||
proxy.setOwner(owner);
|
proxy.setOwner(owner);
|
|
@ -1,4 +1,4 @@
|
||||||
pragma solidity ^0.4.23;
|
pragma solidity ^0.5.0;
|
||||||
|
|
||||||
|
|
||||||
library SafeMath {
|
library SafeMath {
|
||||||
|
@ -9,8 +9,8 @@ library SafeMath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract UserAuth {
|
|
||||||
|
|
||||||
|
contract UserAuth {
|
||||||
using SafeMath for uint;
|
using SafeMath for uint;
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
|
|
||||||
|
@ -33,16 +33,6 @@ contract UserAuth {
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAuth(address src) internal view returns (bool) {
|
|
||||||
if (src == address(this)) {
|
|
||||||
return true;
|
|
||||||
} else if (src == owner) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOwner(address owner_) public auth {
|
function setOwner(address owner_) public auth {
|
||||||
owner = owner_;
|
owner = owner_;
|
||||||
emit LogSetOwner(owner, false);
|
emit LogSetOwner(owner, false);
|
||||||
|
@ -61,18 +51,20 @@ contract UserAuth {
|
||||||
emit LogSetGuardian(guardian_);
|
emit LogSetGuardian(guardian_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAuth(address src) internal view returns (bool) {
|
||||||
|
if (src == address(this)) {
|
||||||
|
return true;
|
||||||
|
} else if (src == owner) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
contract UserNote {
|
contract UserNote {
|
||||||
event LogNote(
|
event LogNote(bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint wad, bytes fax);
|
||||||
bytes4 indexed sig,
|
|
||||||
address indexed guy,
|
|
||||||
bytes32 indexed foo,
|
|
||||||
bytes32 indexed bar,
|
|
||||||
uint wad,
|
|
||||||
bytes fax
|
|
||||||
) anonymous;
|
|
||||||
|
|
||||||
modifier note {
|
modifier note {
|
||||||
bytes32 foo;
|
bytes32 foo;
|
||||||
|
@ -81,31 +73,41 @@ contract UserNote {
|
||||||
foo := calldataload(4)
|
foo := calldataload(4)
|
||||||
bar := calldataload(36)
|
bar := calldataload(36)
|
||||||
}
|
}
|
||||||
emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
|
emit LogNote(
|
||||||
|
msg.sig,
|
||||||
|
msg.sender,
|
||||||
|
foo,
|
||||||
|
bar,
|
||||||
|
msg.value,
|
||||||
|
msg.data
|
||||||
|
);
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface LogicRegistry {
|
interface LogicRegistry {
|
||||||
function getLogic(address logicAddr) external view returns(bool);
|
function getLogic(address logicAddr) external view returns (bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// checking if the logic proxy is authorised
|
// checking if the logic proxy is authorised
|
||||||
contract UserLogic {
|
contract UserLogic {
|
||||||
address public logicProxyAddr;
|
address public logicProxyAddr;
|
||||||
function isAuthorisedLogic(address logicAddr) internal view returns(bool) {
|
function isAuthorisedLogic(address logicAddr) internal view returns (bool) {
|
||||||
LogicRegistry logicProxy = LogicRegistry(logicProxyAddr);
|
LogicRegistry logicProxy = LogicRegistry(logicProxyAddr);
|
||||||
return logicProxy.getLogic(logicAddr);
|
return logicProxy.getLogic(logicAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// UserProxy
|
// UserProxy
|
||||||
// Allows code execution using a persistant identity This can be very
|
// Allows code execution using a persistant identity This can be very
|
||||||
// useful to execute a sequence of atomic actions. Since the owner of
|
// useful to execute a sequence of atomic actions. Since the owner of
|
||||||
// the proxy can be changed, this allows for dynamic ownership models
|
// the proxy can be changed, this allows for dynamic ownership models
|
||||||
// i.e. a multisig
|
// i.e. a multisig
|
||||||
contract UserProxy is UserAuth, UserNote, UserLogic {
|
contract UserProxy is UserAuth, UserNote, UserLogic {
|
||||||
|
|
||||||
constructor(address logicProxyAddr_, uint activePeriod_) public {
|
constructor(address logicProxyAddr_, uint activePeriod_) public {
|
||||||
logicProxyAddr = logicProxyAddr_;
|
logicProxyAddr = logicProxyAddr_;
|
||||||
lastActivity = block.timestamp;
|
lastActivity = block.timestamp;
|
||||||
|
@ -114,13 +116,7 @@ contract UserProxy is UserAuth, UserNote, UserLogic {
|
||||||
|
|
||||||
function() external payable {}
|
function() external payable {}
|
||||||
|
|
||||||
function execute(address _target, bytes memory _data)
|
function execute(address _target, bytes memory _data) public payable auth note returns (bytes memory response) {
|
||||||
public
|
|
||||||
auth
|
|
||||||
note
|
|
||||||
payable
|
|
||||||
returns (bytes memory response)
|
|
||||||
{
|
|
||||||
require(_target != address(0), "user-proxy-target-address-required");
|
require(_target != address(0), "user-proxy-target-address-required");
|
||||||
require(isAuthorisedLogic(_target), "logic-proxy-address-not-allowed");
|
require(isAuthorisedLogic(_target), "logic-proxy-address-not-allowed");
|
||||||
lastActivity = block.timestamp;
|
lastActivity = block.timestamp;
|
||||||
|
@ -135,10 +131,10 @@ contract UserProxy is UserAuth, UserNote, UserLogic {
|
||||||
returndatacopy(add(response, 0x20), 0, size)
|
returndatacopy(add(response, 0x20), 0, size)
|
||||||
|
|
||||||
switch iszero(succeeded)
|
switch iszero(succeeded)
|
||||||
case 1 {
|
case 1 {
|
||||||
// throw if delegatecall failed
|
// throw if delegatecall failed
|
||||||
revert(add(response, 0x20), size)
|
revert(add(response, 0x20), size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
5
migrations/1_initial_migration.js
Normal file
5
migrations/1_initial_migration.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const Migrations = artifacts.require('./Migrations.sol')
|
||||||
|
|
||||||
|
module.exports = async deployer => {
|
||||||
|
await deployer.deploy(Migrations)
|
||||||
|
}
|
5
migrations/2_contract_migrations.js
Normal file
5
migrations/2_contract_migrations.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const ownableFactory = artifacts.require('Ownable.sol')
|
||||||
|
|
||||||
|
module.exports = async deployer => {
|
||||||
|
await deployer.deploy(ownableFactory)
|
||||||
|
}
|
10
mocha-smart-contracts-config.json
Normal file
10
mocha-smart-contracts-config.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"reporterEnabled": "mocha-junit-reporter, eth-gas-reporter",
|
||||||
|
"mochaJunitReporterReporterOptions": {
|
||||||
|
"mochaFile": "./test-results/test-contract-results.xml"
|
||||||
|
},
|
||||||
|
"reporterOptions": {
|
||||||
|
"currency": "USD",
|
||||||
|
"gasPrice": 21
|
||||||
|
}
|
||||||
|
}
|
68
package.json
Normal file
68
package.json
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
{
|
||||||
|
"name": "smart-contract-starter",
|
||||||
|
"description": "Boilerplate for your next Smart Contract, made simple.",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"author": "Ravindra Kumar <ravidsrk@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "truffle.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"ganache": "ganache-cli -e 300 -p 9545 -m 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat' --accounts 30 > /dev/null &",
|
||||||
|
"stop": "sudo kill `sudo lsof -t -i:9545`",
|
||||||
|
"test": "npm run ganache sleep 5 && npm run lint ./ && npm run solium && truffle test && npm run stop",
|
||||||
|
"test:gas-reporter": "GAS_REPORTER=true npm run test",
|
||||||
|
"test-ci": "GAS_REPORTER=true npm run ganache sleep 5 && npm run lint ./ && npm run solium && truffle test",
|
||||||
|
"coverage": "./node_modules/.bin/solidity-coverage",
|
||||||
|
"lint": "eslint ./test",
|
||||||
|
"lint:fix": "eslint ./ --fix",
|
||||||
|
"solium": "solium -d contracts/",
|
||||||
|
"solium:fix": "solium -d contracts/ --fix",
|
||||||
|
"build": "npm run clean:contracts && truffle compile"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bn.js": "^4.11.8",
|
||||||
|
"dotenv": "^6.2.0",
|
||||||
|
"ethereumjs-wallet": "^0.6.3",
|
||||||
|
"npm-check-updates": "^2.15.0",
|
||||||
|
"openzeppelin-solidity": "^2.0.0",
|
||||||
|
"truffle": "^5.0.0",
|
||||||
|
"truffle-hdwallet-provider": "^1.0.1",
|
||||||
|
"web3": "^1.0.0-beta.37",
|
||||||
|
"webpack": "^4.28.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-cli": "^6.26.0",
|
||||||
|
"babel-eslint": "10.0.1",
|
||||||
|
"babel-polyfill": "^6.26.0",
|
||||||
|
"babel-preset-env": "^1.7.0",
|
||||||
|
"babel-preset-es2015": "6.24.1",
|
||||||
|
"babel-preset-stage-2": "6.24.1",
|
||||||
|
"babel-preset-stage-3": "6.24.1",
|
||||||
|
"babel-register": "6.26.0",
|
||||||
|
"chai": "4.2.0",
|
||||||
|
"chai-as-promised": "7.1.1",
|
||||||
|
"chai-bignumber": "3.0.0",
|
||||||
|
"coveralls": "3.0.2",
|
||||||
|
"eslint": "5.10.0",
|
||||||
|
"eslint-config-prettier": "^3.3.0",
|
||||||
|
"eslint-config-standard": "^12.0.0",
|
||||||
|
"eslint-plugin-babel": "^5.3.0",
|
||||||
|
"eslint-plugin-compat": "^2.6.3",
|
||||||
|
"eslint-plugin-import": "2.14.0",
|
||||||
|
"eslint-plugin-node": "8.0.0",
|
||||||
|
"eslint-plugin-prettier": "^3.0.0",
|
||||||
|
"eslint-plugin-promise": "4.0.1",
|
||||||
|
"eslint-plugin-security": "^1.4.0",
|
||||||
|
"eslint-plugin-standard": "^4.0.0",
|
||||||
|
"eth-gas-reporter": "^0.1.12",
|
||||||
|
"ganache-cli": "^6.2.5",
|
||||||
|
"mocha-junit-reporter": "^1.18.0",
|
||||||
|
"mocha-multi-reporters": "^1.1.7",
|
||||||
|
"prettier": "^1.16.4",
|
||||||
|
"prettier-plugin-solidity-refactor": "^1.0.0-alpha.14",
|
||||||
|
"solidity-coverage": "0.5.11",
|
||||||
|
"solium": "1.1.8"
|
||||||
|
}
|
||||||
|
}
|
31
test/Ownable.test.js
Normal file
31
test/Ownable.test.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
const { assertRevert } = require('./helpers/general')
|
||||||
|
|
||||||
|
const Ownable = artifacts.require('Ownable')
|
||||||
|
|
||||||
|
contract('Ownable', accounts => {
|
||||||
|
let ownable
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
ownable = await Ownable.new()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should have an owner', async () => {
|
||||||
|
const owner = await ownable.owner()
|
||||||
|
assert.isTrue(owner !== 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes owner after transfer', async () => {
|
||||||
|
const other = accounts[1]
|
||||||
|
await ownable.transferOwnership(other)
|
||||||
|
const owner = await ownable.owner()
|
||||||
|
|
||||||
|
assert.isTrue(owner === other)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should prevent non-owners from transfering', async () => {
|
||||||
|
const other = accounts[2]
|
||||||
|
const owner = await ownable.owner.call()
|
||||||
|
assert.isTrue(owner !== other)
|
||||||
|
await assertRevert(ownable.transferOwnership(other, { from: other }))
|
||||||
|
})
|
||||||
|
})
|
158
test/helpers/general.js
Normal file
158
test/helpers/general.js
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
const { BN } = web3.utils
|
||||||
|
|
||||||
|
const decimals18 = new BN(10).pow(new BN(18))
|
||||||
|
const bigZero = new BN(0)
|
||||||
|
const addressZero = `0x${'0'.repeat(40)}`
|
||||||
|
const bytes32Zero = '0x' + '00'.repeat(32)
|
||||||
|
const gasPrice = new BN(5e9)
|
||||||
|
|
||||||
|
const assertRevert = async promise => {
|
||||||
|
try {
|
||||||
|
await promise
|
||||||
|
assert.fail('Expected revert not received')
|
||||||
|
} catch (error) {
|
||||||
|
const revertFound = error.message.search('revert') >= 0
|
||||||
|
assert(revertFound, `Expected "revert", got ${error} instead`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const assertJump = async promise => {
|
||||||
|
try {
|
||||||
|
await promise
|
||||||
|
assert.fail('Expected invalid opcode not received')
|
||||||
|
} catch (error) {
|
||||||
|
const invalidOpcodeReceived = error.message.search('invalid opcode') >= 0
|
||||||
|
assert(
|
||||||
|
invalidOpcodeReceived,
|
||||||
|
`Expected "invalid opcode", got ${error} instead`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const assertThrow = async promise => {
|
||||||
|
try {
|
||||||
|
await promise
|
||||||
|
} catch (error) {
|
||||||
|
// TODO: Check jump destination to destinguish between a throw
|
||||||
|
// and an actual invalid jump.
|
||||||
|
const invalidOpcode = error.message.search('invalid opcode') >= 0
|
||||||
|
// TODO: When we contract A calls contract B, and B throws, instead
|
||||||
|
// of an 'invalid jump', we get an 'out of gas' error. How do
|
||||||
|
// we distinguish this from an actual out of gas event? (The
|
||||||
|
// testrpc log actually show an 'invalid jump' event.)
|
||||||
|
const outOfGas = error.message.search('out of gas') >= 0
|
||||||
|
const revert = error.message.search('revert') >= 0
|
||||||
|
const exception =
|
||||||
|
error.message.search(
|
||||||
|
'VM Exception while processing transaction: revert'
|
||||||
|
) >= 0
|
||||||
|
assert(
|
||||||
|
invalidOpcode || exception || outOfGas || revert,
|
||||||
|
"Expected throw, got '" + error + "' instead"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.fail('Expected throw not received')
|
||||||
|
}
|
||||||
|
|
||||||
|
const waitForEvent = (contract, event, optTimeout) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
return reject(new Error('Timeout waiting for contractEvent'))
|
||||||
|
}, optTimeout || 5000)
|
||||||
|
|
||||||
|
const eventEmitter = contract.contract.events[event]()
|
||||||
|
eventEmitter
|
||||||
|
.on('data', data => {
|
||||||
|
eventEmitter.unsubscribe()
|
||||||
|
clearTimeout(timeout)
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.on('changed', data => {
|
||||||
|
clearTimeout()
|
||||||
|
eventEmitter.unsubscribe()
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.on('error', err => {
|
||||||
|
eventEmitter.unsubscribe()
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const areInRange = (num1, num2, range) => {
|
||||||
|
const bigNum1 = new BN(num1.toString())
|
||||||
|
const bigNum2 = new BN(num2.toString())
|
||||||
|
const bigRange = new BN(range.toString())
|
||||||
|
|
||||||
|
if (bigNum1.equals(bigNum2)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const larger = bigNum1.gt(bigNum2) ? bigNum1 : bigNum2
|
||||||
|
const smaller = bigNum1.lt(bigNum2) ? bigNum1 : bigNum2
|
||||||
|
|
||||||
|
return larger.sub(smaller).lt(bigRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getNowInSeconds = () => new BN(Date.now()).div(1000).floor(0)
|
||||||
|
|
||||||
|
const trimBytes32Array = bytes32Array =>
|
||||||
|
bytes32Array.filter(bytes32 => bytes32 != bytes32Zero)
|
||||||
|
|
||||||
|
const getEtherBalance = address => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
web3.eth.getBalance(address, (err, res) => {
|
||||||
|
if (err) reject(err)
|
||||||
|
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTxInfo = txHash => {
|
||||||
|
if (typeof txHash === 'object') {
|
||||||
|
return txHash.receipt
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
web3.eth.getTransactionReceipt(txHash, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendTransaction = args => {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
web3.eth.sendTransaction(args, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
resolve(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
decimals18,
|
||||||
|
bigZero,
|
||||||
|
addressZero,
|
||||||
|
bytes32Zero,
|
||||||
|
gasPrice,
|
||||||
|
assertRevert,
|
||||||
|
assertJump,
|
||||||
|
assertThrow,
|
||||||
|
waitForEvent,
|
||||||
|
areInRange,
|
||||||
|
getNowInSeconds,
|
||||||
|
trimBytes32Array,
|
||||||
|
getEtherBalance,
|
||||||
|
getTxInfo,
|
||||||
|
sendTransaction
|
||||||
|
}
|
18
truffle-box.json
Executable file
18
truffle-box.json
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"ignore": [
|
||||||
|
"README.md",
|
||||||
|
"package-lock.json"
|
||||||
|
],
|
||||||
|
"commands": {
|
||||||
|
"Compile contracts": "truffle compile",
|
||||||
|
"Migrate contracts": "truffle migrate",
|
||||||
|
"Test contracts": "truffle test",
|
||||||
|
"Run eslint": "npm run lint",
|
||||||
|
"Run solium": "npm run solium",
|
||||||
|
"Run solidity-coverage": "npm run coverage",
|
||||||
|
"Run lint, solium, and truffle test": "npm run test"
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"post-unpack": "npm install"
|
||||||
|
}
|
||||||
|
}
|
56
truffle.js
Normal file
56
truffle.js
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
require('dotenv').config()
|
||||||
|
const HDWalletProvider = require('truffle-hdwallet-provider')
|
||||||
|
|
||||||
|
const rinkebyWallet =
|
||||||
|
'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat'
|
||||||
|
const rinkebyProvider = new HDWalletProvider(
|
||||||
|
rinkebyWallet,
|
||||||
|
'https://rinkeby.infura.io/'
|
||||||
|
)
|
||||||
|
|
||||||
|
const ropstenWallet =
|
||||||
|
'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat'
|
||||||
|
const ropstenProvider = new HDWalletProvider(
|
||||||
|
ropstenWallet,
|
||||||
|
'https://ropsten.infura.io/'
|
||||||
|
)
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
migrations_directory: './migrations',
|
||||||
|
networks: {
|
||||||
|
test: {
|
||||||
|
host: 'localhost',
|
||||||
|
port: 9545,
|
||||||
|
network_id: '*',
|
||||||
|
gas: 6.5e6,
|
||||||
|
gasPrice: 5e9,
|
||||||
|
websockets: true
|
||||||
|
},
|
||||||
|
ropsten: {
|
||||||
|
network_id: 3,
|
||||||
|
gas: 6.5e6,
|
||||||
|
gasPrice: 5e9,
|
||||||
|
provider: () => ropstenProvider
|
||||||
|
},
|
||||||
|
rinkeby: {
|
||||||
|
network_id: 4,
|
||||||
|
gas: 6.5e6,
|
||||||
|
gasPrice: 5e9,
|
||||||
|
provider: () => rinkebyProvider
|
||||||
|
}
|
||||||
|
},
|
||||||
|
solc: {
|
||||||
|
optimizer: {
|
||||||
|
enabled: true,
|
||||||
|
runs: 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mocha: {
|
||||||
|
reporter: 'mocha-multi-reporters',
|
||||||
|
useColors: true,
|
||||||
|
enableTimeouts: false,
|
||||||
|
reporterOptions: {
|
||||||
|
configFile: './mocha-smart-contracts-config.json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user