Please read here.
Please read on the issuance curve in our whitepaper, you may also refer to curve models in doc.
Mechanism is explained in source code here and on diagram below.
You may also check fork arbitrage mechanism here.
Without container:
yarn # installs all dependencies
yarn testrpc # run testnet
# open new terminal window
yarn deploy localhost
Within container:
docker build . -t neufund/platform-contracts
docker run -it -p 8545:8545 --name platform-contracts --rm neufund/platform-contracts yarn testrpc
# open new terminal window
docker exec platform-contracts yarn deploy localhost
We keep current artifacts here: https://github.com/Neufund/platform-contracts-artifacts. Artifacts are updated on each merge to master and deployed to Neufund private network (see networks below.). For each deployed network we preserve Truffle build artifacts and provide additional deployment metadata file (see artifacts repo above for details).
You can easily export build artifacts for your local deployment (like you want to test platform-frontend).
- select a directory for artifacts. Easiest way is to use
platform-contracts-artifacts
folder by issuinggit clone https://github.com/Neufund/platform-contracts-artifacts.git
- run deploy script in the container mapping chosen host folder
- you have your artifacts
platform-contracts-artifacts/<network name>
when deploy command completes
docker build . -t neufund/platform-contracts
docker run -it -p 8545:8545 --name platform-contracts --rm -v $(pwd)/platform-contracts-artifacts:/usr/src/platform-contracts/platform-contracts-artifacts neufund/platform-contracts yarn testrpc
docker exec --user $(id -u):$(id -g) platform-contracts yarn deploy localhost
yarn testrpc
will launch ganache-cli
with 9 pre-defined Ethereum accounts. We keep the same set
of accounts for our parity dev and parity test networks. You can find our parity dev node here
(https://github.com/Neufund/parity-instant-seal-byzantium-enabled) and use it as alternative to
ganache-cli
. See description of Truffle networks below. We have BIP32 restore codes for those
accounts (see below).
Please do not develop inside container!
Supported compiler: Version: 0.4.23+commit.124ca40d.Linux.g++
Always use
yarn truffle compile --all
or
yarn build
Truffle is not able to track dependencies correctly and will not recompile files that import other files
You should consider replacing javascript compiler with solc
, this will increase your turnover
several times. Use following patches over cli.bundle.js (into which truffle is packed)
curl -L --fail -o solc4.23 https://github.com/ethereum/solidity/releases/download/v0.4.23/solc-static-linux
chmod +x solc4.23
sudo cp solc4.23 /usr/bin/
yarn solctruffle
you can count current LOC with sloc
find contracts -path contracts/test -prune -a -path contracts/Snapshot/Extras -prune -a -path contracts/SnapshotToken/Extensions -prune -o -name *.sol | xargs sloc -a sol=js
yarn format:fix
You can flatten your smart contract and create one large .sol
file using
yarn truffle-flattener <smart-contract-path> <target directory>
example:
yarn truffle-flattener ./contracts/Eurotoken.sol ./postFlatten
Run
yarn flatten
in order to flatten all smart contracts included in the deployment processes
In order to verify a smart-contract on Etherscan you will have to provide a:
- flattened version of the smart contract source code
- bytecode string with deployed constructor Arguments.
The verification processes can be done here
In order to give an in-depth walkthrough, this section will explain the processes of verifying the Neumark smart contract
- Run
yarn flatten
in order to flatten all smart contracts up for deployment and output to./build/flatten
- Run the Smart-Contract-Watch from
moe/coded-constructor
branch and start from the contract creation block. If done correctly this will return the used constructor arguments needed. In the case of Neumark it was00000000000000000000000088144fa49c6b97b845c4eb7a1f61c52f49303210
00000000000000000000000038e0e54c1c7c405cec81c6ad66aff65700be5951
Currently, this processes works only if all variables were static. - Open etherscan
- Enter smart-contract address for the case of Neumark
0xd8f36d2de608987a8b6e19016a20645032ae6647
- Enter smart contract name as written in the
.sol
file in this caseNeumark
- Choose the correct compiler in our case
solc 0.4.15+commit
with Optimization enabled - Copy the flattened source code from
./build/flatten/Neumark.sol
and paste in the source code section. - Copy the constructor arguments and paste in the relative sections
- Verify and Publish
Run
yarn prefillAgreements
In order to prefill legal Agreements with correct addresses of contracts and roles. The script
automatically fills both NEUMARK TOKEN HOLDER AGREEMENT
and RESERVATION AGREEMENT
with correct
addresses for
- Neumark contract address
- Commitment contract Address
- PLATFORM_OPERATOR_REPRESENTATIVE
run
yarn uploadAgreements <IPFS node address> [filePath1,filePath2 ...]
In order to upload files to IPFS you can run this script, you must provide an IPFS node address. This tool will use IPFS api in order to upload files to IPFS You can leave files empty to upload default files
Currently default files are
./legal/NEUMARK TOKEN HOLDER AGREEMENT.out
./legal/RESERVATION AGREEMENT.out
Calling constant method that reverts
- pre-byzantium and post byzantium parity will return
result: 0x
(0x in result field of JSON-RPC response). Clearly it does not look as the error code ;> and if you are using web3, it will try to decode and fail specific expection per expected data type returned (like invalid BigNumber or address), some types will just succeed so BEWARE testrpc
will return exception stringinvalid opcode
and stack trace inerror
field of JSON-RPC responseganache
will return exception stringVM Exception ...
and stack trace inerror
field of JSON-RPC response
Executing transactions that revert
- pre-byzantium parity - normal transaction object and transaction receipt are returned (just with all gas used). there is no other way to detect revert besides generating and checking events in case of success (so lack of event is error situation). this is very weak
- post-byzantium parity and other nodes - there is
status
field in transaction receipt! use this. use Neufund modified truffle that recognize this situation (https://github.com/Neufund/truffle),neufund
branch. testrpc
will return exception stringinvalid opcode
and stack trace inerror
field of JSON-RPC responseganache
will return exception stringVM Exception ...
and stack trace inerror
field of JSON-RPC response
Executing transactions that revert with status string
Ganache-cli finally returns revert codes in exception string, this also applies to reverts in
eth_call
. Parity however has undefined behavior on eth_call with revert - AFAIK it returns whole
EVM stack frame
yarn test:coverage
you will find coverage report in coverage/index.html
. We are using version custom version of
solidity-coverage
. Versions later than 0.2.2
introduce a problem as described in
sc-forks/solidity-coverage#118 which results in balances increasing due to
code execution and basically the result balance is unpredictable due to returned stipend. This issue
prevents test that check balances to run properly.
Custom version fixes two other bugs:
- For large trace files,
readFileSync
will fail silently, stream is used to read lines instead exec
on child process will kill child if stdout buffer overflows, buffer was increased to 10MB- It refers to testrpc
4.0.1
that has stipend not modified.
Solidity code coverage runs own testrpc node (modified). You can run this node via
./node_modules/ethereumjs-testrpc-sc/build/cli.node.js --gasPrice 1 --gasLimit 0xfffffffffff -v
and execute tests via coverage
network to check coverage behavior.
To run all tests, use the following
yarn test
To run single test, use following syntax
yarn truffle test test/LockedAccount.js test/setup.js
To run single test case from a test use following syntax
it.only('test case', ...
There are simulated commitments in ICBM/Commitment.js which are very long. Execute those with
special truffle network inprocess_massive_test
yarn truffle test test/Commitment.js test/setup.js --network inprocess_massive_test
Remarks on current state of tests in truffle and testrpc
Applies to truffle 3.4.9
with ganache 2.1.0
.
Truffle uses snapshotting mechanism (evm_snapshot
and evm_revert
) to revert to clean state
between test suites. Current version of ganache does not handle it correctly and will fail on revert
with some probability. This makes running large test suites hard as there is high chance of ganache
to crash.
As snapshotting is used to recover blockchain state after deployment scripts, we have no use of that mechanism and it can be disabled. Here is a patch to test runner https://github.com/trufflesuite/truffle-core/blob/master/lib/testing/testrunner.js
TestRunner.prototype.resetState = function(callback) {
callback();
};
Snapshotting has other problems that also makes it useless for state management in our tests. trufflesuite/ganache#7 Hopefully PRs solving this are pending.
Remarks on non-ganache testing You are able to run test on parity nodes, evm_increaseTime is not supported so those tests will fail. Here is dockerized node that works. https://github.com/Neufund/parity-instant-seal-byzantium-enabled
Modified version of truffle is referenced for running test cases.
- Revert and snapshot are removed from
truffle-core
(https://github.com/Neufund/truffle-core/commit/83404a758a684e8d3d4806f24bc40a25c0817b79) - trufflesuite/truffle#569 is fixed as testing overloaded
transfer
is impossible (https://github.com/Neufund/truffle-contract/commit/ecae09942db60039f2dc4768ceeb88776226f0ca) - Works with byzantium enabled Parity nodes
There are several conventions in naming truffle networks used for deployment. Network with names
ending with _live
will be deployed in production mode which means that:
- Live accounts addresses as specified in
config.js
will be assigned to roles. - Live smart contracts parameters as specified in
config.js
will be deployed - Agreements will not be attached.
- Deployer will set ACCESS_CONTROLLER as secondary access control admin address and will remove
itself as global ACCESS_CONTROLLER (see
6_relinquish_control.js
)
Other networks will be deployed in test mode which means that:
- All roles are assigned to accounts[0] or
from
(if specified in truffle network), which is also deployer. This account controls everything. - Modify
config.js
as you wish to deploy with custom smart contract parameters. - Everything is deployed and set up. Commitment contract should be ready to go after deployment.
- Fixtures will be deployed in test mode.
Special networks
- simulated_live will be deployed as live network but is intended to be used against ganache. Roles will be assigned to ganache provided accounts. It is intended to test various administrative operations (like enabling/disabling transfers) before live deployment.
- all networks ending with test and _coverage will not deploy anything. They are intended to be used by test runner
yarn truffle migrate --reset --network simulated_live
Below are important networks from truffle.js
|Network|Mode|Description| |-------|----|-----------|
|localhost|test|will attach to anything at port 8545 and set deployer to
0x8a194c13308326173423119f8dcb785ce14c732b
, intended to run with yarn testrpc
or with parity
instant seal| |inprocess|test|will use in-process ganache
so you do not have to run anything|
|nf_private|test|will deploy to neufund private network where
0x8a194c13308326173423119f8dcb785ce14c732b
is the deployer|
Contracts are deployed in following order
- RoleBasedAccessControl - used to set up access permissions in other contracts, see below
- EthereumForkArbiter - used to indicate fork that is actually supported (legally and technically),
- Neumark - ERC20/223 and snapshotable token representing Neumark reward to investors,
- EtherToken - encapsulates Ether as a token
- EuroToken - represents Euro as a token (EUR-T), see below,
- LockedAccount(EtherToken) - represents investor's individual investment account with unlock date, for Ether investment,
- LockedAccount(EuroToken) - represents investor's individual investment account with unlock date, for EUR-T investment,
- Commitment - represents ICBM process with pre-ICO, and ICO stages, whitelisting, possibility to invest in Ether/EUR-T and other features.
Commitment contracts currently serves as a 'Universe'. All contracts, agreements and parameters we officially support during ICBM may be found in it or in other aggregated contracts.
Several contracts require parameters to be set in constructors as specified below. Once set those parameters cannot be changed.
LockedAccount
- LOCK_DURATION - duration of lock after which
unlock
comes without penalty, in seconds - PENALTY_FRACTION - unlock penalty as fraction of investment amount, where 10**18 is 100%, 10**17 is 10% etc.
Commitment
- START_DATE - start date of ICBM (see
StateMachine
contract for process details), as Unix/Ethereum timestamp (UTC), - CAP_EUR - safety cap (in EUR-T) which corresponds to maximum number of Neumarks that may be issued during ICBM, in "wei" (10**-18 parts of EUR-T).
- MIN_TICKET_EUR - minimum ticket in EUR-T, represented as above
- ETH_EUR_FRACTION - EUR-T to ETH rate used during whole ICBM. we use constant rate to compute Neumark reward, there's no oracle.
- PLATFORM_OPERATOR_WALLET - see below.
Agreements
- RESERVATION_AGREEMENT - ipfs link to Reservation Agreement, attached to
Commitment
contract - NEUMARK_HOLDER_AGREEMENT - ipfs link to Neumark Token Holder Agreeement attached to
Neumark
contract
Please note that several ICBM duration parameters are encoded in StateMachine
contract. You may
choose to change them form test deployments.
Several accounts are required to deploy on mainnet
due to many roles with specific permissions
that are required to control ICBM and Neumark token. Below is a list of those roles.
Role | Description | Mainnet account | Scope |
---|---|---|---|
LOCKED ACCOUNT ADMIN | May attach controller, set fee disbursal pool and migration in Locked Account contract | PO Admin | LockedAccount |
WHITELIST ADMIN | May setup whitelist and abort Commitment contract with curve rollback | PO Admin | Commitment |
NEUMARK ISSUER | May issue (generate) Neumarks (only Commitment or ETOs contract may have this right) | N/A | Commitment |
TRANSFER ADMIN | May enable/disable transfers on Neumark | (Commitment contract to enable trading after ICBM) | Neumark |
RECLAIMER | may reclaim tokens/ether from contracts | PO Admin | global role |
PLATFORM OPERATOR REPRESENTATIVE | Represents legally platform operator in case of forks and contracts with legal agreement attached | PO Management | global role |
EURT DEPOSIT MANAGER | Allows to deposit EUR-T and allow addresses to send and receive EUR-T | PO Admin | EuroToken |
ACCESS CONTROLLER | Assigns permissions to addresses and may change access policy for a contract | PO Admin | global role |
PLATFORM OPERATOR WALLET | Stores Platform Operator Neumark reward and (temporarily) unlock penalties | PO Wallet | N/A |
Please note that ACCESS CONTROL role is initially assigned to an address of the deploying account
(like in Ownable
pattern). This permission is then relinquished to PO Admin account. Accounts are
separate physical devices (Nano Ledger S). Please note that account used to deploy has no other uses
and its private key can be safely destroyed after control is relinquished.
Euro Token is heavily policed token, where only holders with permission may receive or send EUR-T.
Transfer permissions are managed by EURT DEPOSIT MANAGER role which also is the sole issuer of
EUR-T. Issue EUR-T
operation enables issued address to receive EUR-T (and is done only against
KYCed accounts) so after deployment no further changes to transfer permissions are necessary. Please
note that permission to transfer from
enables such address to act as a broker (transferFrom
)
which may be used by addresses without such permission to send EUR-T to other address. This property
is used by Commitment and LockedAccount contracts to deposit EUR-T during ICBM process.
EURT DEPOSIT MANAGER issues to -> investor (has transfer to) which approves -> Commitment contract (has transfer from and to) to -> transfer to LockedAccount contract (transfer from and to)
Full list of transfer permission is as follows.
who | transfer to | transfer from |
---|---|---|
EUR-T investor | Y | N |
Commitment | Y | Y |
LockedAccount | Y | Y |
Both LockedAccount
instances must be linked to Commitment contract (which becomes their
controller) to be able to store investor's assets and provide unlock mechanism. Both LockedAccount
must also have unlock penalty disbursal pool set for unlock
operation to work. Per whitepaper,
until platform is deployed, penalties are stored in Platform Operator wallet (however
LockedAccount
supports disbursal contracts as well). Linking requires LOCKED ACCOUNT ROLE
.
Neumark
and Commitment
contracts need to be provided ipfs link to legal agreement. Otherwise all
functions of those contracts that require it will revert. In case of main network this must happen
via transaction from PLATFORM OPERATOR REPRESENTATIVE
using its respective Nano S and it's not
done in deployment scripts in this repo. In case of other networks, mock legal agreements will be
immediately attached.
Whitelist may be set during Before
state of Commitment
contract. This is not part of deployment
script in this repo. Setting whitelist requires WHITELIST ADMIN
role.