Smart Contracts Catalogue - Neufund/platform-contracts GitHub Wiki

Access Control contracts group

Contracts in this group provide a mixin AccessControlled that adds ability to limit execution of public functions via only modifier. AccessControlled implements IAccessControlled which allows to change the controller if such controller allows (see setAccessPolicy which itself uses only modifier). Primary use case for changing the controller is to totally separate access control in given contract by providing its private controller instance.

Controlled contracts are controlled by a controller contract implementing IAccessPolicy interface (see code, it's documented).

Platform used role-based access policy (RoleBasedAccessPolicy) where execution access is allowed per role which is required in only modifier. ACLs (which msg.sender addresses belong to which role in which contract) are defined RoleBasedAccessPolicy. For more flexibility, special msg.sender and contract contexts were defined: GLOBAL contract context that applies to all controlled contracts and EVERYONE msg.sender which allows to execute given role to everyone (see burn function of Neumark contract).

Code and behaviors are documented with 100% test coverage. Read code and tests for details.

RoleBasedAccessPolicy was deployed during ICBM and we intend to use it forever.

Roles are defined in StandardRoles (just a role to change ACLs and access policy) and AccessRoles which defines all roles recognized by platform contracts.

Note that we still use other access control schemes, for example in ETOCommitment contract there are functions that only Company (Issuer) or Nominee can execute and this is done via locally implemented modifiers

Universe

Universe contract server as a root of trust of Platform. Add that Universe points to are supported and official "Neufund Platform" contracts. Supported contracts are classified by KnownInterfaces which are unique identifiers of services provided by those contracts (can be implemented differently by particular contract with different ABI). There are two types of services:

  1. Singletons - there just one instance of service present in Universe. Setting new instance, replaces old one. Example: Neumark token, RoleBasedAccessPolicy
  2. Collections - there may be many such instances present in Universe. You need to add and remove instances explicitely. Example: ETO Commitment contracts, Equity Token contracts

There is test coverage for essential functions, missing tests are declared

we plan to add implementation identifier on top of known service id for easier versioning and UI generation

Agreement

Concept is well explained in IAgreement and Agreement mixin with corresponding tests. Best Agreement usage is Neumark.sol. Also we have a nice diagram: https://github.com/Neufund/platform-contracts#smart-contract-and-legal-contract-parity

IdentityRegistry

We use it to store claims from a single issuer. Otherwise we have identical mechanics to uPort implementation (which is simple and cheap as well ;> https://github.com/uport-project/ethereum-claims-registry/blob/master/contracts/EthereumClaimsRegistry.sol

For more details please read IIdentityRegistry and IdentityRegistry implementation. Please take a look at IdentityRecord, there is a little bit of assembly trickery and homework is to explain how it works

Token Rate Oracle and Gas Exchange

Token rate oracle provides price feeds of token pairs. Oracle is centralized and only a special platform role may provide rates. ITokenExchangeRateOracle.sol defines how rates are read (please note that we provide timestamps where rate was obtained). Writing is not part of oracle spec. Look at implementation of reading and writing in SimpleExchange.sol where public methods are sufficiently documented.

Gas Exchange lets users without any Ether to exchange "other token" (ie. Euro Token) to ether. It happens via backend service that has permission to use exchange functionality and will throttle such operations so exchanged amounts are very small. Exchange process also requires ERC20 allowance in the "other token" for the exchange contract to do the transferFrom of "other token" to itself (as a part of "ether purchase" transaction).

We intend to use it with Euro Token to onboard new users with gas. If user has no gas then how he makes allowance to exchange contract which is Ethereum transaction? In case of Euro Token he does not. There is always small constant allowance to simple exchange embedded in Euro Token Controller. That's explained separately.

Gas Exchange interface is defined in IGasExchange.sol and implemented by SimpleExchange.sol. This interface is not perfect and possibly we should split it into IGas and IExchange parts so IExchange can handle token rate writes. Tbd.

There is a test coverage for happy path in SimpleExchange.js

EtherToken and ICBMEtherToken

ICBMEtherToken is ERC223 compatible token that is used to keep ether of ICBM investors. Currently all ether is kept as ICBMLockedAccount balance (so this contract is the only token holder). We didn't intend to migrate from this contract however a few things changed

  • Ethereum community settled on different callback function name for ERC223 (compare IERC223LegacyCallback vs IERC223Callback)
  • We need a few convenience methods that will make our UX better.

So we offer new EtherToken. It's based on zeppelin/StandardToken (which does not have much in common with Zeppelin now). It's not a snapshot token. Code base is simple read it!

Now we have two convenience methods

  • depositAndTransfer
  • withdrawAndSend

Homework is to explain what they do. The problem solved is as follows: as investor you have ether on your wallet but you can also have ether in ether token. Now you want to invest whole amount. or withdraw to other wallet (whole amount). we do not want to bother investor with such complexity...

look at the tests of ICBMEtherToken and EtherToken - how they are standardized. tests for convenience methods are missing. this code was never run

EuroToken and EuroTokenController

Token controller is a pattern that let's you abstract away checking who can do transfer to whom (also deposit, withdraw, allowance). We use it to limit transfers in Euro Token but also in Equity Token (where you need voting to enable transfers). Token controller is a powerful pattern. Euro Token is even simpler than Ether Token, derives from the same code base.

  • look how token controller is attached via modifiers
  • look how permanent allowance for gas exchange works (in transferFrom overrid). super ugly trick, I know Now the token controller. The only complicated thing is logic to allow transfer to happen in isTransferAllowedPrivate
  • you can explicitely enable an address to send or receive transfers (setAllowedTransfer...) - it's an mechanism from old ICBMEuroToken. It overrides other logic
  • you can receive transfer if you are ETO contract and sender has KYC
  • you can send when you are ETO contract and sender has KYC (refund, payout of fund-raising amount to Nominee)

Also look how euro token controller settings are changed and what special transfer permissions are set

There is interesting quirk for transfer with a broker. I'll explain that later.

EuroTokenController has separate tests, we still are missing several tests they must be implemented

PlatformTerms, ETOTerms, DurationTerms and ShareholderRights

Required read: https://github.com/Neufund/platform-backend/wiki/5.7.-Use-Case-ETO-Listing - the role of each contract is explained.

ETOTerms contains several function to manage whitelist and also abstracts away computations of min - max tickets, token prices etc. for particular investor. This (in theory) allows to change discount and pricing structure (for example: introduce price curves) without changing ETO Commitment.

For each contract there is unfinished test suite. Objective is to finish them. Also PlatformTerms are not fully tested. See todo in deploymentContracts.js helper.

ETOTerms will get upgrade for whitelist discounts: https://github.com/Neufund/platform-contracts/issues/130

ICommitment, IETOCommitment and ETO State Machine implementation

ICommitment - describes basic interface of all commitments (ETOs, ICBM, other ICOs) that may happen on the platform. It requires proper tracking of investments (via events), investment happening only via ERC223 compatible payment tokens (fallback) and basic state: like commitment is finished and if it succeeded. IETOCommitment - describes ETO Commitment process, defines states (IETOCommitmentStates), and method to check ETO progress. It also introduces concept of ETOCommitment observer. Observer is a callback interface that is called on every state transition of IETOCommitment. Currently the observer is Equity Token Controller. This will be explained later. ETOTimedStateMachine - implements time induced state machine. It develops concepts from ICBM/Commitment/ICBMStateMachine. All methods that participate in state (require to be run in certain state and be able to modify state) must use withStateTransition modifier. Please its code. It basically explains how state machine works.

  • before body is executed, we check time. if we see that state transition is required we do it (one by one - if states must be skipped)
  • after body is executed, we check if we should change state due to business logic (for example max cap was reached and we should finalize ETO)
  • derived contract has no access to state or timestamps. it is wired to state changes and can also influence state by implementing internal observer interface (will be extracted for clarity)
  • by implementing that interface, derived contract is aware of time induced transitions and can override those (example: next default state is claim which happens after 30 days but derived class overrides with refund because max cap was not reached)
  • it can also induce state transition due to business logic.

happy path was tested, the task is to provide full tests for state machine by implementing placeholding eto commitment contract and checking all possible state changes (with overrides and mocked logic) - see tests for ICBM/Commitment where state machine is tested extensively

ETO Commitment - investment via payment token

Investment happens via supported payment token via ERC223 callback. We'll get through the whole process from the investor's side

  • reserve (commit)
  • claim
  • refund
  • payout

we mention ICBM wallets but this is another lesson

Equity Token and Equit Token Controller

Equity Token is based on Snapshot Token which is based on MiniMe token from Giveth. Snapshots are necessary to fulfill "earned" rights of token holders. Those rights come with having the balance and include voting power, dividends, information and anything you can imagine. Those rights you do not lose with selling the token: you should be able to take past dividends and your past votes should still count. Here is more on snaphotting: https://github.com/Neufund/EIPs/blob/token-with-snapshots/eip-token-with-snapshots.md Here is more on snapshot token derivation: https://github.com/Neufund/platform-contracts/tree/master/contracts/SnapshotToken Other important property of Equity Token is that is it legally binding: it has corresponding legal agreement attached via IAgreement interface

EquityToken and EquityTokenController

Equity token is very simple and deals just with ownership and transfer rights. It also preserves past balances. It's ERC223 token. Equity Token Controller is the same interface we had for euro token but in this case it represents a company (issuer) of the token and is responsible for executing rights of the token holders. In principle it says

  • how tokens are issued and destroyed
  • who can transfer to whom
  • how you can take dividend
  • what is the voting procedure (governance)

basically Equity Token Controller can be any governance mechanism even a DAO. In case of Equity Token it is a contract representing off-chain company and company governance (which is very democratic).

We'll implement many versions of the controller. For the launch we have PlaceholderEquityTokenController which provides only information and token issuance rights. It's intended to be upgraded with full governance version.

Exercises: finish EquityToken and Placeholder tests. most of those are already declared