- This README shows how to work with our smart contracts.
- ECOSYSTEM.md gives an architectural overview and detailed information about the individual contracts
- TEST-AGAINST-GETH.md explains how to run the tests against
geth
instead of truffle'sganache
- WORST-CASE-SCENARIOS.md analyzes what could go wrong along with potential mitigation steps
- Node.js (we always work with the latest LTS release)
- yarn
- Python 3 for running mythril
-
Create local
.env
:cp .env.example .env
This is necessary to configure the right
$NODE_PATH
for easier pathing, for example. -
Install dependencies:
yarn
-
Install mythril, a security analysis tool for Ethereum smart contracts
# You will need python3 and pip3 for this to work pip3 install mythril
The directory frozen/
contains smart contract files and related tests that are considered frozen. The concept of 'frozen contracts' means that these contracts have been deployed to mainnet using a specific Solidity compiler version. Frozen contracts should not be upgraded or can not be upgraded. By filling out parts in our mainnet ecosystem, e.g. rich state that's hard to migrate to new contracts, more and more contracts won't be upgradable anymore. Only logic related to POA Tokens is designed to be upgradable through the delegatecall
-pattern we apply. Since Truffle currently supports only one Solidity compiler version for the command truffle compile
, we must make sure that all .sol
files remain in contracts/
. Thus frozen contracts represent a duplicate of contracts with the compiler version with which the contract was deployed to mainnet.
Currently, the following contracts are frozen:
BrickblockToken
(version 0.4.18): The ICO is over and this contract holds significant state on mainnet. Cannot be upgraded.BrickblockAccount
(version 0.4.24): Since the ICO was finalized, this contract holds the company BBKs. Cannot be upgraded.ContractRegistry
(version 0.4.24): Holds references to other mainnet contracts. Referenced contracts, including frozenBrickblockAccount
have been initialized with theContractRegistry
address. Thus, this contract cannot be upgraded.CustomPOAToken
(version 0.4.18): Not used anymore.- All other contracts can potentially still be upgraded although being deployed on mainnet. However, upgrades included re-registrations of contract addresses in
ContractRegistry
.
Generally, the current mainnet code of a smart contract can be found by first checking frozen/
. If it's not there, the mainnet code can be found in contracts/
.
Note: As the output bytecode changes between Solidity compiler versions, we have no guarantee that our tested contracts in contracts/
(single compiler version) actually behave the same way as the mainnet ecosystem (different compiler versions). This is a risk that we should address when Truffle supports compiling contracts under different compiler versions.
Tests are split in three categories: Main tests, Stress tests and Frozen Contract tests. In development mode we run all tests against truffle's ganache. Before submitting contracts to auditors or deploying contracts to Mainnet we always run the tests against geth
, too. TEST-AGAINST-GETH.md explains how this works. It is a heck of a lot slower but it is closer to the production environment in which our contracts will eventually run so it gives as a higher degree of certainty that everything really works as expected.
Unit tests, testing the general functionality of our contracts.
Run them with:
yarn test
Stress tests are implemented to mimic real world scenarios, such as creating reasonable random transaction amounts with maximum available iterations and users. That's why it is recomended to run these tests using an external ganache with the config mentioned below to assure there is enough money and users to put contracts under pressure. The stress tests throw random values at those contracts where integer division can result in minor inaccuracies. These tests ensure that this "dust" doesn't get too big to be of significance. They are split out of the normal tests because they take a very long time to run due to the amount of transactions being performed.
Run them with:
- (Optional but recommended step) Run an external ganache with the following config, users: 50, default ether balance: 1000
- Each stress test should be run individually. To run a stress test:
yarn test stress-tests/[testFilename.js] --skip-migrations
Tests of frozen contracts can be run with:
yarn test:frozen
You can check for common smart contract vulnerabilities in our code with mythril:
yarn test:mythril
Linting both *.js
and *.sol
files can be done using:
yarn lint
Lint .sol
only:
yarn lint:sol
Lint .js
only:
yarn lint:js
Deploying with truffle will execute the migrations/2_deploy_contracts.js which does the following:
- Choose the right network configuration (depends on the
--network
argument) - Deploy registry
- Deploy other contracts
- Add all contracts to registry
- Set ETH/EUR exchange rate
- Run
finalizeTokenSale
on BBK contract in order to activate the BBK/ACT/FMR ecosystem - Distribute BBK tokens to
accounts[2-5]
Note: Make sure you have at least 6 accounts on your node setup
account[0]
is the owneraccount[1]
is the bonus address for BBKaccount[2-5]
are BBK token holders
-
Run
yarn truffle develop --network dev
-
In the truffle console, run
migrate --reset
to deploy fresh contract instances -
Play around with the contracts, e.g. add an issuer via
PoaManager.deployed() .then(poaManager => { poaManager.addIssuer(web3.eth.accounts[3]) })
There are pre-defined actions you can call with migrations
- --forceDeploy, --fd: Deploys contracts given as parameters. 'all' means deploy everything. Can be used with --uec to deploy only selected contracts and use the rest from the registry.
- --register, -r: Registers deployed contracts to Contract Registry
- --setRate, --sr: Updates ExchangeRate Contract to fetch 'EUR' currency from oraclize api (on ganache it uses a constant value instead of a real one)
- --finalizeBbk, --fb: on BBK contract:
- calls
changeFountainContractAddress
- if the network is not mainnet, it distributes BBK token to Accounts[4,6]
- calls
finalizeTokenSale
- calls
unpause
- calls
- --addIssuer, --ab: Adds accounts[1] as issuer to PoaManager
- --deployPoa, --dp: Deploys a sample PoaToken with Issuer account
- --addToWhiteList, --aw: Adds accounts[3] to whitelist
- --default, -a: Executes
register
,setRate
,finalizeBbk
,addIssuer
,addToWhitelist
with the same order. - --useExistingContracts, --uec: Uses existing contracts instead of deploy if they exist in "config/deployed-contracts.js"' with the chosen network. If it cannot find a pre-defined address, it deploys a new contract.
- --changeOwner, --co: Changes owner to
NEW_OWNER
given in.env
file. Only useful if it deploys to mainnet. - --help: Displays posible options
NOTES:
- You have to provide one of
--forceDeploy [arguments]
or--useExistingContracts
to have the essential functionality. - Only essential actions are grouped by
default
action to keep it more flexible
- Start the Ganache app (make sure it's running on
8545
in the settings!) or runyarn ganache-cli -p 8545
- Run
yarn migrate:dev --[action name]
examples:
# Deploy with default actions
yarn migrate:dev --forceDeploy all --default
# Use pre-deployed contracts
yarn migrate:dev --useExistingContracts --default
# Short version
yarn migrate:dev --uec -def
# Deploy with some actions
yarn migrate:dev --forceDeploy all --register --setRate --finalizeBbk
# Deploy selected contracts only and use the rest from the registry
# Note: If contract addresses are not found in `.env` file for dev network or `config/deployed-contracts.js` for testnets, deployment script deploys a new one
yarn migrate:dev --forceDeploy AccessToken BrickblockAccount --useExistingContracts --register
# Forcing to use a contract outside of registry
# First you need to put it inside `.env` file for dev network or `config/deployed-contracts.js`
# then run:
yarn migrate:dev --useExistingContracts --other params
# To deploy POA Token
# Make sure everything is deployed, registered, BBK finalized, currency set, issuers added and investors whitelisted
# To customize your token, use --deployPoa-[sub argument name]. See help for the full list.
yarn migrate:dev --useExistingContracts -deployPoa
# To see the full list of commands, ask for help
yarn migrate:dev --help
- Make sure you set
TESTNET_MNEMONIC
andINFURA_API_KEY
in.env
file for your HD wallet - Make sure you set
ContractRegistry
address field under the right network Id if you don't do a full deployment. - Everything else is the same as local deployment
- Run
yarn migrate:[network name] --def --fd all
The network name can be rinkeby
, kovan
, or ropsten
When you'd like to interact with deployed contracts on a local testnet, check that truffle.js
setting for dev
matches your local testrpc / ganache-cli settings and run:
- Make sure you you are running a local testnet and deployed the contracts using deployment script.
- Make sure you put
ContractRegistry
address to.env
file. (see.env.example
for an example)
There are some arguments to know before moving on:
- --execute, --exec: you have to give a contract name as parameter to this argument. Currently it only supports
PoaToken
- --execute-functionName, --exec-fn: function name to be executed
- --execute-arguments, --exec-args: function arguments. Any argument with the exact same order the function receives, seperated by comma or space
- --execute-address, --exec-addr:
PoaToken
contract address. It can be a real address or index number in PoaManager token list. - --execute-txConfig, --exec-tc: tx params for the function to executed. Ex: '{"from":"0x1c34e1325d5193cdf95fc6e863edc789a798a23e", "value": 10000000}'
Example for starting Eth Sale
yarn migrate:dev --uec --exec PoaToken --exec-addr 0x3e5d48f04b942fce33f12eb582aa4364106962f5 --exec-fn startEthSale'
Example for buying poa token
# --exec-addr can be either a real POA token address or an index number on POA Manager token list
yarn migrate:dev --uec --exec PoaToken --exec-addr 0 --exec-fn buy --exec-tc '{"value":100000, "from":"0xb95cb8ffbdf31b9dc19caad6208a49c8248b6249"}'
yarn truffle console --network dev
.
This will open a node.js repl session, with all the compiled contracts available as usual (ie. BrickblockToken.deployed()
or PoaToken.at(some-address)
).
If you'd like to interact with contracts on a public testnet (ie. rinkeby, kovan) then we have a command that also uses truffle console
and additionally makes use of the library truffle-hdwallet-provider
. This allows us to specify a remote node to connect with and a mnemonic to give access to accounts in that HDWALLET (like MetaMask does).
NOTE: any valid bip39 mnemonic will work fine unless you want to send transactions or ETH, then you will need ETH in the sending account like usual. Feel free to use the example HDWALLET_MNEMONIC
below.
An example for rinkeby is:
HDWALLET_MNEMONIC="ridge approve ten planet fever oyster cargo upper frequent humor hen alcohol" INFURA_URL="https://rinkeby.infura.io" yarn repl