These smart contracts implement tokenize.it's tokenized cap table management. Using tokenize.it, it is possible to:
- generate tokens that grant economical rights to the token holder
- sell these tokens to investors either publicly or privately
- distribute tokens to employees or partners, either directly or through a vesting contract
yarn add @tokenizeit/contracts
or
npm install @tokenizeit/contracts
- clone repository:
git clone --recurse-submodules [email protected]:corpus-ventures/tokenize.it-smart-contracts.git
- enter project root folder:
cd tokenize.it-smart-contracts
- if repository was cloned without submodules, init submodules now (not necessary if cloning command above was used):
git submodule update --init --recursive
- init project:
yarn install
- run tests:
yarn test
If you are missing dependencies:
- node/npm:
- install nvm
nvm install 18
nvm use 18
- yarn:
npm install yarn
- foundry: install guide
More dev information can be found here:
- Using tokenize.it's legal approach, a company can create tokens that grant economical rights to the token holders. The best smart contract to create these tokens is Token.sol
- Funds are raised through selling of these tokens:
- a customized deal to a specific investor can be realized through the PrivateOffer.sol contract.
- crowdinvesting, which is open to everyone meeting the requirements, is done through the Crowdinvesting.sol contract
- Employee participation is easy:
- direct distribution of tokens (does not need another smart contract)
- vesting can be realized using the Vesting.sol contract
The requirements for an address to send or receive tokens are checked against the AllowList.sol contract. Fees are collected according to the settings in FeeSettings.sol. Tokenize.it will deploy and manage at least one AllowList and one FeeSettings contract.
The smart contracts can be found in the contracts/ folder.
All contracts are based on the well documented and tested OpenZeppelin smart contract suite.
It is possible to directly use all smart contracts in this project, without going through the platform's frontend at all. In order to improve UX, though, a frontend will be offered. In order to improve UX even more, the user will not have to pay gas when using this frontend. This is achieved through three approaches:
- the platform executes transactions like contract deployments that do not require the user's signature
- actions concerning our own contracts that require the user's approval are executed as meta-transactions, using EIP-2711
- granting allowances on external currencies is possible through EIP-2612 (ERC20Permit), which is widely adopted. This is not in the scope of this documentation though.
Several of the contracts implement EIP-2771, and therefore use a trusted forwarder. The forwarder will be set in the constructor and there is no way to change it after deployment. The forwarder used will be the openGSN v2 forwarder deployed on mainnet. Some information about this contract:
-
Deployment on Ethereum Mainnet: 0xAa3E82b4c4093b4bA13Cb5714382C99ADBf750cA
- deployed 2022-04-21
- official resources
- Visit on etherscan (see transactions here)
- This dashboard lists the forwarder as second most active forwarder contract with over 2000 transactions executed
- used in our tests.
-
Deployment on Gnosis Chain: 0x7eEae829DF28F9Ce522274D5771A6Be91d00E5ED
- deployed 2021-04-29
- official resources
- visit on blockscout
The platform will maintain a hot wallet (EOA) in order to send transactions to the forwarder contract. This results in the following flow:
- contract A supports EIP-2771 and uses
forwarder
as its (one and only, immutable) trusted forwarder - user (investor or founder) wants to use function
a(...)
of contractA
and uses the platform for this - platform (tokenize.it) prepares meta transaction payload and asks user for signature
- user signs the payload with their own key (using metamask or similar)
- platform now has payload and signature and uses its hot wallet to call
forwarder.execute(payload, signature, ...)
- forwarder verifies signature and payload on-chain
- forwarder executes
A.a(...)
with parameters according to payload - contract
A
only verifies it is being called by the ONE forwarder it trusts. It does not verify any signatures. This is why the forwarder is called trusted forwarder: it is trusted to do the verification. - contract
A
executes functiona(...)
in the name of user
This is a trustless process, because:
- the forwarder contract can not be updated
- the trusted forwarder setting in contract A is immutable
- signature verification is executed on-chain
Open gas station network provides tools to execute meta transactions without involving a third party hot wallet. Tokenize.it does not plan on using these tools though. Exclusively using a hot wallet for transaction execution does not harm security at all.
The hot wallet approach might reduce availability, which is not a major concern for this use case (the hot wallet being available whenever the frontend is available is good enough). Keep in mind that EIP-2771 is purely offered for UX reasons. All smart contracts can be used directly, too, further reducing concerns about hot wallet availability.
An Openzeppelin Defender Relay may be used as hot wallet.
The currencies used for payments must conform to the ERC20 standard. This standard is not very strict though. It can be implemented in many ways, including incompatible and even malicious contracts. Therefore, tokenize.it will limit the currencies supported in the web frontend to this list:
- WETH: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
- WBTC: 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599
- USDC: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
- EUROC: 0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c
- DAI: 0x6B175474E89094C44Da98b954EedeAC495271d0F
- EURe: 0x3231cb76718cdef2155fc47b5286d82e6eda273f
These implementations have been checked and tested to work well with the tokenize.it smart contracts. The use of any other currencies is HIGHLY DISCOURAGED and might lead to:
- loss of funds due to various attacks
- partial payments due to the currency deducting a transfer fee
- other issues
To enforce the use of trusted currencies only, they are added to the AllowList.sol contract with the special TRUSTED_CURRENCY
bit. PrivateOffers and Crowdinvesting campaigns will only accept currencies that are on the AllowList and have the TRUSTED_CURRENCY
bit set. This makes using a malicious currency by mistake impossible, but still allows either the platform or other operators of their own AllowLists to edit and extend the list of supported currencies.
The following resources are available regarding the contracts:
- Basic high level overview
- Basic dev overview
- More detailed walkthrough
- In-depth explanation: please read the contracts
- Specification
- Price format explainer
- Fee Collection
- Deployment
- Testing.
- npm publishing.
- Remaining questions: please get in touch at [email protected]