Repository: district0x/district0x-network-token
Branch: master
Commit: a002f3931298
Files: 74
Total size: 455.1 KB
Directory structure:
gitextract__46f1lkn/
├── .gitignore
├── .travis.yml
├── CONTRIBUTION_FLOW.md
├── LICENSE
├── README.md
├── compile-solidity.sh
├── docker-builds/
│ └── ui/
│ ├── Dockerfile
│ ├── contribution.district0x.io
│ ├── default
│ └── nginx.conf
├── docker-push.sh
├── project.clj
├── resources/
│ └── public/
│ ├── contracts/
│ │ ├── build/
│ │ │ ├── ApproveAndCallFallBack.abi
│ │ │ ├── ApproveAndCallReceiver.abi
│ │ │ ├── BasicToken.abi
│ │ │ ├── Controlled.abi
│ │ │ ├── Controller.abi
│ │ │ ├── D0xToken.abi
│ │ │ ├── District0xContribution.abi
│ │ │ ├── District0xNetworkToken.abi
│ │ │ ├── ERC20.abi
│ │ │ ├── ERC20Basic.abi
│ │ │ ├── GrantsControlled.abi
│ │ │ ├── HasNoTokens.abi
│ │ │ ├── LimitedTransferToken.abi
│ │ │ ├── MiniMeToken.abi
│ │ │ ├── MiniMeTokenFactory.abi
│ │ │ ├── MultisigWallet.abi
│ │ │ ├── Ownable.abi
│ │ │ ├── Pausable.abi
│ │ │ ├── SafeMath.abi
│ │ │ ├── Shareable.abi
│ │ │ ├── StandardToken.abi
│ │ │ ├── TokenController.abi
│ │ │ ├── TokenVesting.abi
│ │ │ └── VestedToken.abi
│ │ └── src/
│ │ ├── District0xContribution.sol
│ │ ├── District0xNetworkToken.sol
│ │ ├── ERC20.sol
│ │ ├── ERC20Basic.sol
│ │ ├── GrantsControlled.sol
│ │ ├── HasNoTokens.sol
│ │ ├── LimitedTransferToken.sol
│ │ ├── MiniMeToken.sol
│ │ ├── MultisigWallet.sol
│ │ ├── Ownable.sol
│ │ ├── Pausable.sol
│ │ ├── SafeERC20.sol
│ │ ├── SafeMath.sol
│ │ ├── Shareable.sol
│ │ ├── SingleFileContribution.sol
│ │ ├── TokenVesting.sol
│ │ ├── VestedToken.sol
│ │ ├── math/
│ │ │ └── SafeMath.sol
│ │ ├── minime_interface/
│ │ │ ├── ApproveAndCallFallback.sol
│ │ │ ├── Controlled.sol
│ │ │ └── TokenController.sol
│ │ ├── orig/
│ │ │ ├── ERC20.sol
│ │ │ ├── LimitedTransferToken.sol
│ │ │ ├── MiniMeToken.sol
│ │ │ └── VestedToken.sol
│ │ └── ownership/
│ │ └── Ownable.sol
│ ├── index.html
│ └── less/
│ └── district0x.main.less
├── src/
│ └── cljs/
│ └── contribution/
│ ├── api.cljs
│ ├── components/
│ │ └── main_panel.cljs
│ ├── constants.cljs
│ ├── core.cljs
│ ├── db.cljs
│ ├── events.cljs
│ ├── styles.cljs
│ └── subs.cljs
└── test/
└── contribution/
├── cmd.cljs
└── tests.cljs
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/target
/classes
/checkouts
pom.xml
pom.xml.asc
*.jar
*.class
/.lein-*
/.nrepl-port
.hgignore
.hg/
.idea
contribution.iml
/figwheel_server.log
/resources/public/js/compiled/
/test-fig-out/
/test-fig-compiled/
/test-compiled/
/node_modules/
package-lock.json
package.json
/tests/
resources/public/css/
================================================
FILE: .travis.yml
================================================
language: clojure
script: echo "JUST DEPLOYING"
notifications:
email:
recipients:
- juan@district0x.io
slack:
on_success: always
on_failure: always
rooms:
- district0x:53vhalUfg0MitsQwzjP5PWdd#travis-ci
env:
global:
- secure: xt6stp9H+jVZuCdL2Hmc4AGv6N4rbooy9cLXPY7N7v6Q9QGnOtOV+mIZkGxI1P3OYE1m+fKW1lEAynxIkJgVOkNlp+JLF279PZaWYrmpHwueX33ElYd8BQelmlYev84jWT4OmFhinWWzfoQHoBTYTpc1bLp/xIlhrFrANLiB4wThq4t+cZcpk3srjcxFL8xS2V6sHzJzBxu637W5vYV7deuHR0pMZJfmxfL252zzMtZYYKxi+3NnFh1gTg8v+w0Whre7elNd7Obq9JypnMjWZRVQ7WnFKQFKZr09cQ3NhuGtA069/Cju9f70cZDnySRxegZ8EZFPhl9tOOjTcagque4eOuylLtRkop3DE4i0xBvptxrXystdPk1nexJimOeZYjukklVRULVRUsTOF7k5g1lriIszPYg+3bIvKRWVFFOrpq47Cud87horbj0Pij+wlmwCNFGkq1lfGMTIN7IUpAC0e3QTzyoBZyEcRn4hSWmbDUvq9C23ZAQuSVbEDcbkt6Xudoyl3O6egGVxRe4Wv552xMNmp57W/vUWhcotzqCyucXYlcQnimyVgy7jKlG7Jn61AyHT7hQMw0qAo99S2vhytJqt+LDrnWLACJ6MhaoKQSmGFvVN96sUXtcEwsmrXbCBol7uT7alP6kE7Hq/llk88e6Mvn4+ANDbUjCnnM0=
- secure: 3a07x1H5oEZ10CleLEVJuL/KPE1GVGRFY5MnoMdQ31kCbg+vlVaD9bFXs02Ipck4ELRABzWgM4pFNRlGlFE9GaUDrFEfmC90x8dSFVgATR9nTbkDI5mGUjPNlGQq5z9dvTmP11s/Le1/WS0WxJ0bvl8g3eevozsVcGcXuPsDf77Ghbfo7I5CttotEx+/i9vZZRfiLMMpm+5gRndjAEtqD2wGTrOyBlFfHwfRVR/XadUJIV7r1WxpCQbu4eXcLx95Sv09yBRujMM5xiCD4V50PPaDRbUZFwoCZcPuSzxSOW2pWYbGsesjTwaY/d/Y+nr8zHglcGx/jB7a949Ugk9zr12ttQsf51AfJZHNKHz4J/DCCDIDT+JOSjtGlAIAUvvhvUrfsPa5tHn0c/xJxBRCyFR0je+1TLKPHp0V1WlHIZWxfo2uDNZJf7HGG7fFOPueJNDry3+zVlsBZvXRN6MSE+MxcHBSZP5vTwv3OfVVMNt9Pg3ZkmpHK9x5Kx7xx67TW3d4WKB9HVwdYUm8JnFwJ1f/PzbTv77H27VJzO79Qpd1n2HSKQZiwkiTioxhUlu0b6xadPhHC6XTdgGHwzkCaxIR3ljg8+So3y3DVOMu8M5yXC+7Awwn2NmOWnPXK0cGX7HY1OZrKKtIp6E7gH/+M1mQxzaEuIlc5/YNsiqSMjM=
services:
- docker
deploy:
- provider: script
script: bash docker-push.sh prod
on:
branch: production
================================================
FILE: CONTRIBUTION_FLOW.md
================================================
# district0x Contribution Period Flow (DNT Token Sale)
### Instantiation
#### 1. Deploy contribution contract [District0xContribution.sol](/resources/public/contracts/src/District0xContribution.sol)
district0x contribution contract will be deployed at least 5 days prior to the beginning of the contribution period.
Parameters:
- _Owners_: Addresses allowed to confirm contract transactions that require multiple signatures. Such as enabling or cancelling contribution period.
- _Required_: Number of signatures required to run multi-signature transaction
- _Wallet_: Multi-signature wallet holding raised funds
- _Cofounder 1_: Address of Matus
- _Cofounder 2_: Address of Joe
- _Early Sponsor_: Address of our early sponsor
- _Advisers_: 4 addresses of advisers consisting of: Luis Cuende from Aragon, Carl Bennett from Status, our legal adviser and community advisers wallet.
From community advisers wallet, DNT rewards will be send after sale to community members listed in this [spreadsheet](https://docs.google.com/spreadsheets/d/11Kw5JK2YTFQzoC5yHH7EcGJAF3Ve9ypz3M6J12h0PmU/edit#gid=0).
#### 2. Deploy MiniMeTokenFactory [MiniMeToken.sol](/resources/public/contracts/src/MiniMeToken.sol)
MiniMeTokenFactory contract must be deployed, so DNT Token becomes clonable.
No parameters.
#### 3. Deploy token contract [District0xNetworkToken.sol](/resources/public/contracts/src/District0xNetworkToken.sol)
Parameters:
- _Controller_: Address of District0xContribution contract. Its address will be the only one allowed to generate predetermined
amount of DNT tokens. District0xContribution doesn't implement function to transfer controller ownership, therefore additional
DNT tokens can never be generated.
- _TokenFactory_: Address of earlier deployed MiniMeTokenFactory
#### 4. Set DNT Token address `District0xContribution.setDistrict0xNetworkToken()`
This method sets address of District0xNetworkToken in contribution contract. At this moment, exactly 1,000,000,000 DNT
tokens is generated and assigned to contribution contract.
Parameters:
- _district0xNetworkToken_: Address of earlier deployed District0xNetworkToken
#### 5. Set contribution period parameters `District0xContribution.setContribPeriod()`
This method sets up contribution period parameters and also vesting for founders, early sponsor and advisers. Note, after
setting up, contribution period is still not valid. To be valid it must be confirmed by multiple signatures (see following step).
Parameters:
- _Contribution Period Index_: **0** Index number of contribution period to be set up (0, 1 or 2)
- _Soft Cap Amount_: **10 Mil USD in ETH** Soft Cap for a contribution period
- _After Soft Cap Duration_: **48 hours** Time to the end of contribution from the moment of reaching soft cap (unless reaching Hard Cap)
- _Hard Cap Amount_: **50 Mil USD in ETH** When reached this amount, the contribution period ends instantly
- _Start Time_: **July 18, 3:00pm UTC** Beginning of a contribution period
- _End Time_: **August 1, 3:00pm UTC** End of a contribution period, unless Soft or Hard cap is reached
#### 6. Enable contribution period `District0xContribution.enableContribPeriod()`
This method will be executed only with multiple signatures 4/6 of our team and trusted individuals from Ethereum community (listed in our whitepaper).
It will make a contribution period confirmed with current parameters.
Parameters:
- _Contribution Period Index_: **0** Index number of contribution period to be enabled (0, 1 or 2)
### Contribution
#### 7. Buy DNT tokens `District0xContribution.contribute()` or `District0xContribution.fallback()`
This method will save your address and amount of your contribution. If you contribute multiple times from the
same address amounts will be added up. Note, since we'll allocate DNT proportionally to the contributed amount, DNT
tokens will not be send to contributors immediately. Distribution will happen shortly after sale. Contributed
Ether is transferred to our multi-signature wallet after each contribution. Note, **maximum gas price** that can be
used for contribution is **50Gwei**, otherwise transaction will fail!
No parameters
#### 8. Emergency stop `District0xContribution.emergencyStop()`
In case of emergency, district0x is able to pause contribution period
### After Contribution
#### 9. Send DNT to contributors `District0xContribution.compensateContributors()`
This method is called by owner after contribution period ends to distribute DNT in proportional manner.
In case of many contributors will need to be executed multiple times, due to gas limit restrictions.
Parameters:
- _Contribution Period Index_: **0** Index number of contribution period to be enabled (0, 1 or 2)
- _offset_: Number of first contributors to skip.
- _limit_: Maximum number of contributors compensated with this transaction. Offset and limit parameters are
used to "paging" through contributors
#### 10. Enable DNT transfers `District0xContribution.enableDistrict0xNetworkTokenTransfers()`
This method is called by owner after DNT tokens were distributed to all contributors. DNT transfers should be
enabled in matter of hours after end of contribution period. We'll enable them as soon as we're sure that
distribution of DNT went without bugs.
No Parameters.
#### 11. Cancel following contribution period `District0xContribution.cancelContribPeriod()`
Second and third contribution period might be subject to cancellation if district0x doesn't need more funds to
achieve goals stated in our roadmap. In this case tokens allocated for a contribution period will be destroyed.
This method must be executed by multi-signature.
Parameters:
- _Contribution Period Index_: **1** Index number of contribution period to be enabled (1 or 2)
================================================
FILE: LICENSE
================================================
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial code and
documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and are
distributed by that particular Contributor. A Contribution 'originates' from
a Contributor if it was added to the Program by such Contributor itself or
anyone acting on such Contributor's behalf. Contributions do not include
additions to the Program which: (i) are separate modules of software
distributed in conjunction with the Program under their own license
agreement, and (ii) are not derivative works of the Program.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents" mean patent claims licensable by a Contributor which are
necessarily infringed by the use or sale of its Contribution alone or when
combined with the Program.
"Program" means the Contributions distributed in accordance with this
Agreement.
"Recipient" means anyone who receives the Program under this Agreement,
including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide, royalty-free copyright license to
reproduce, prepare derivative works of, publicly display, publicly perform,
distribute and sublicense the Contribution of such Contributor, if any, and
such derivative works, in source code and object code form.
b) Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide, royalty-free patent license under
Licensed Patents to make, use, sell, offer to sell, import and otherwise
transfer the Contribution of such Contributor, if any, in source code and
object code form. This patent license shall apply to the combination of the
Contribution and the Program if, at the time the Contribution is added by the
Contributor, such addition of the Contribution causes such combination to be
covered by the Licensed Patents. The patent license shall not apply to any
other combinations which include the Contribution. No hardware per se is
licensed hereunder.
c) Recipient understands that although each Contributor grants the licenses
to its Contributions set forth herein, no assurances are provided by any
Contributor that the Program does not infringe the patent or other
intellectual property rights of any other entity. Each Contributor disclaims
any liability to Recipient for claims brought by any other entity based on
infringement of intellectual property rights or otherwise. As a condition to
exercising the rights and licenses granted hereunder, each Recipient hereby
assumes sole responsibility to secure any other intellectual property rights
needed, if any. For example, if a third party patent license is required to
allow Recipient to distribute the Program, it is Recipient's responsibility
to acquire that license before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient
copyright rights in its Contribution, if any, to grant the copyright license
set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under
its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties and
conditions, express and implied, including warranties or conditions of title
and non-infringement, and implied warranties or conditions of merchantability
and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for
damages, including direct, indirect, special, incidental and consequential
damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are offered
by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such
Contributor, and informs licensees how to obtain it in a reasonable manner on
or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained within
the Program.
Each Contributor must identify itself as the originator of its Contribution,
if any, in a manner that reasonably allows subsequent Recipients to identify
the originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities with
respect to end users, business partners and the like. While this license is
intended to facilitate the commercial use of the Program, the Contributor who
includes the Program in a commercial product offering should do so in a
manner which does not create potential liability for other Contributors.
Therefore, if a Contributor includes the Program in a commercial product
offering, such Contributor ("Commercial Contributor") hereby agrees to defend
and indemnify every other Contributor ("Indemnified Contributor") against any
losses, damages and costs (collectively "Losses") arising from claims,
lawsuits and other legal actions brought by a third party against the
Indemnified Contributor to the extent caused by the acts or omissions of such
Commercial Contributor in connection with its distribution of the Program in
a commercial product offering. The obligations in this section do not apply
to any claims or Losses relating to any actual or alleged intellectual
property infringement. In order to qualify, an Indemnified Contributor must:
a) promptly notify the Commercial Contributor in writing of such claim, and
b) allow the Commercial Contributor to control, and cooperate with the
Commercial Contributor in, the defense and any related settlement
negotiations. The Indemnified Contributor may participate in any such claim
at its own expense.
For example, a Contributor might include the Program in a commercial product
offering, Product X. That Contributor is then a Commercial Contributor. If
that Commercial Contributor then makes performance claims, or offers
warranties related to Product X, those performance claims and warranties are
such Commercial Contributor's responsibility alone. Under this section, the
Commercial Contributor would have to defend claims against the other
Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON
AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the
appropriateness of using and distributing the Program and assumes all risks
associated with its exercise of rights under this Agreement , including but
not limited to the risks and costs of program errors, compliance with
applicable laws, damage to or loss of data, programs or equipment, and
unavailability or interruption of operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of the
remainder of the terms of this Agreement, and without further action by the
parties hereto, such provision shall be reformed to the minimum extent
necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Program itself
(excluding combinations of the Program with other software or hardware)
infringes such Recipient's patent(s), then such Recipient's rights granted
under Section 2(b) shall terminate as of the date such litigation is filed.
All Recipient's rights under this Agreement shall terminate if it fails to
comply with any of the material terms or conditions of this Agreement and
does not cure such failure in a reasonable period of time after becoming
aware of such noncompliance. If all Recipient's rights under this Agreement
terminate, Recipient agrees to cease use and distribution of the Program as
soon as reasonably practicable. However, Recipient's obligations under this
Agreement and any licenses granted by Recipient relating to the Program shall
continue and survive.
Everyone is permitted to copy and distribute copies of this Agreement, but in
order to avoid inconsistency the Agreement is copyrighted and may only be
modified in the following manner. The Agreement Steward reserves the right to
publish new versions (including revisions) of this Agreement from time to
time. No one other than the Agreement Steward has the right to modify this
Agreement. The Eclipse Foundation is the initial Agreement Steward. The
Eclipse Foundation may assign the responsibility to serve as the Agreement
Steward to a suitable separate entity. Each new version of the Agreement will
be given a distinguishing version number. The Program (including
Contributions) may always be distributed subject to the version of the
Agreement under which it was received. In addition, after a new version of
the Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly
stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
licenses to the intellectual property of any Contributor under this
Agreement, whether expressly, by implication, estoppel or otherwise. All
rights in the Program not expressly granted under this Agreement are
reserved.
This Agreement is governed by the laws of the State of New York and the
intellectual property laws of the United States of America. No party to this
Agreement will bring a legal action under this Agreement more than one year
after the cause of action arose. Each party waives its rights to a jury trial
in any resulting litigation.
================================================
FILE: README.md
================================================
# district0x Network Token [Join our discord](https://discord.gg/Gjvw7qU)
[](https://travis-ci.org/district0x/district0x-network-token)
Read More:
- [Contribution Period Flow](/CONTRIBUTION_FLOW.md)
## ABIs
Contribution [0xf8094e15c897518b5ac5287d7070ca5850efc6ff](https://etherscan.io/address/0xf8094e15c897518b5ac5287d7070ca5850efc6ff):
```json
[{"constant":true,"inputs":[],"name":"totalContributed","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_minContribAmount","type":"uint256"}],"name":"setMinContribAmount","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"advisers","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"founder1","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"EARLY_CONTRIBUTOR_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"tokenAddr","type":"address"}],"name":"reclaimToken","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"contributors","outputs":[{"name":"amount","type":"uint256"},{"name":"isCompensated","type":"bool"},{"name":"amountCompensated","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"COMMUNITY_ADVISERS_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_softCapAmount","type":"uint256"},{"name":"_afterSoftCapDuration","type":"uint256"},{"name":"_hardCapAmount","type":"uint256"},{"name":"_startTime","type":"uint256"},{"name":"_endTime","type":"uint256"}],"name":"setContribPeriod","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"ADVISER_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"softCapReached","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"endTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"claimTokensFromTokenDistrict0xNetworkToken","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"contributorAddress","type":"address"}],"name":"getContributor","outputs":[{"name":"","type":"uint256"},{"name":"","type":"bool"},{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"maxGasPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"ADVISER_STAKE2","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"contributorsKeys","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"TEAM_VESTING_CLIFF","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"EARLY_CONTRIBUTOR_VESTING_CLIFF","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"enableContribPeriod","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"minContribAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"afterSoftCapDuration","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"emergencyStop","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"isEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getConfiguration","outputs":[{"name":"","type":"bool"},{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"address"},{"name":"_advisers","type":"address[]"},{"name":"","type":"bool"},{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"FOUNDER2_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"CONTRIB_PERIOD2_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"stopped","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"startTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"contributor","type":"address"}],"name":"contributeWithAddress","outputs":[],"payable":true,"type":"function"},{"constant":true,"inputs":[],"name":"founder2","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"earlySponsor","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"CONTRIB_PERIOD3_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"release","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"multisigWallet","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"hardCapReached","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"enableDistrict0xNetworkTokenTransfers","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"tokenTransfersEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"offset","type":"uint256"},{"name":"limit","type":"uint256"}],"name":"getUncompensatedContributors","outputs":[{"name":"contributorIndexes","type":"uint256[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getNow","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"from_","type":"address"},{"name":"value_","type":"uint256"},{"name":"data_","type":"bytes"}],"name":"tokenFallback","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"kill","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"hardCapAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"isContribPeriodRunning","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_maxGasPrice","type":"uint256"}],"name":"setMaxGasPrice","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"contribute","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onApprove","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_district0xNetworkToken","type":"address"}],"name":"setDistrict0xNetworkToken","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"TEAM_VESTING_PERIOD","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"district0xNetworkToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getContribPeriod","outputs":[{"name":"boolValues","type":"bool[3]"},{"name":"uintValues","type":"uint256[8]"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"tokenAddr","type":"address"}],"name":"isTokenSaleToken","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"CONTRIB_PERIOD1_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"EARLY_CONTRIBUTOR_VESTING_PERIOD","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"proxyPayment","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"},{"constant":true,"inputs":[],"name":"softCapAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"FOUNDER1_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"offset","type":"uint256"},{"name":"limit","type":"uint256"}],"name":"compensateContributors","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_multisigWallet","type":"address"},{"name":"_founder1","type":"address"},{"name":"_founder2","type":"address"},{"name":"_earlySponsor","type":"address"},{"name":"_advisers","type":"address[]"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"totalContributed","type":"uint256"},{"indexed":true,"name":"contributor","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"contributorsCount","type":"uint256"}],"name":"onContribution","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"endTime","type":"uint256"}],"name":"onSoftCapReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"endTime","type":"uint256"}],"name":"onHardCapReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"contributor","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"onCompensated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"isStopped","type":"bool"}],"name":"onEmergencyChanged","type":"event"}]
```
DNT [0x0abdace70d3790235af448c88547603b945604ea](https://etherscan.io/address/0x0abdace70d3790235af448c88547603b945604ea):
```json
[{"constant":true,"inputs":[{"name":"_holder","type":"address"}],"name":"tokenGrantsCount","outputs":[{"name":"index","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"creationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"grants","outputs":[{"name":"granter","type":"address"},{"name":"value","type":"uint256"},{"name":"cliff","type":"uint64"},{"name":"vesting","type":"uint64"},{"name":"start","type":"uint64"},{"name":"revokable","type":"bool"},{"name":"burnsOnRevoke","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeController","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_blockNumber","type":"uint256"}],"name":"balanceOfAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_holder","type":"address"},{"name":"_grantId","type":"uint256"}],"name":"tokenGrant","outputs":[{"name":"granter","type":"address"},{"name":"value","type":"uint256"},{"name":"vested","type":"uint256"},{"name":"start","type":"uint64"},{"name":"cliff","type":"uint64"},{"name":"vesting","type":"uint64"},{"name":"revokable","type":"bool"},{"name":"burnsOnRevoke","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_cloneTokenName","type":"string"},{"name":"_cloneDecimalUnits","type":"uint8"},{"name":"_cloneTokenSymbol","type":"string"},{"name":"_snapshotBlock","type":"uint256"},{"name":"_transfersEnabled","type":"bool"}],"name":"createCloneToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_claimer","type":"address"}],"name":"claimTokens","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"}],"name":"lastTokenIsTransferableDate","outputs":[{"name":"date","type":"uint64"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"parentToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"generateTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"grantsController","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"},{"name":"_start","type":"uint64"},{"name":"_cliff","type":"uint64"},{"name":"_vesting","type":"uint64"},{"name":"_revokable","type":"bool"},{"name":"_burnsOnRevoke","type":"bool"}],"name":"grantVestedTokens","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_blockNumber","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"transfersEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"parentSnapShotBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"}],"name":"revokeAllTokenGrants","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"},{"name":"time","type":"uint64"}],"name":"transferableTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"destroyTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"tokens","type":"uint256"},{"name":"time","type":"uint256"},{"name":"start","type":"uint256"},{"name":"cliff","type":"uint256"},{"name":"vesting","type":"uint256"}],"name":"calculateVestedTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeGrantsController","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"tokenFactory","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"},{"name":"_grantId","type":"uint256"}],"name":"revokeTokenGrant","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_transfersEnabled","type":"bool"}],"name":"enableTransfers","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"controller","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[{"name":"_controller","type":"address"},{"name":"_tokenFactory","type":"address"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"grantId","type":"uint256"}],"name":"NewTokenGrant","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_token","type":"address"},{"indexed":true,"name":"_claimer","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"ClaimedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cloneToken","type":"address"},{"indexed":false,"name":"_snapshotBlock","type":"uint256"}],"name":"NewCloneToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Approval","type":"event"}]
```
Multisig [0xd20e4d854c71de2428e1268167753e4c7070ae68](https://etherscan.io/address/0xd20e4d854c71de2428e1268167753e4c7070ae68):
```json
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"owners","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"address"}],"name":"removeOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"revokeConfirmation","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"address"}],"name":"confirmations","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"pending","type":"bool"},{"name":"executed","type":"bool"}],"name":"getTransactionCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"address"}],"name":"addOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"isConfirmed","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"getConfirmationCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"transactions","outputs":[{"name":"destination","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"executed","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getOwners","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"from","type":"uint256"},{"name":"to","type":"uint256"},{"name":"pending","type":"bool"},{"name":"executed","type":"bool"}],"name":"getTransactionIds","outputs":[{"name":"_transactionIds","type":"uint256[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"getConfirmations","outputs":[{"name":"_confirmations","type":"address[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"transactionCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_required","type":"uint256"}],"name":"changeRequirement","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"confirmTransaction","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"destination","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"submitTransaction","outputs":[{"name":"transactionId","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"MAX_OWNER_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"required","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"address"},{"name":"newOwner","type":"address"}],"name":"replaceOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"executeTransaction","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_owners","type":"address[]"},{"name":"_required","type":"uint256"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"Confirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"Revocation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"Submission","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"Execution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"ExecutionFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"OwnerAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"OwnerRemoval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"required","type":"uint256"}],"name":"RequirementChange","type":"event"}]
```
## Technical definition
At the technical level DNT is a ERC20-compliant token, derived from the [MiniMeToken](https://github.com/Giveth/minime) that allows for token cloning (forking), which will be useful for many future usecases.
Vesting functionality derived from [VestedToken](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/VestedToken.sol)
is also built-in into our token. Founders, advisors and early contributor have their tokens vested.
## Contracts
Token:
- [District0xNetworkToken.sol](/resources/public/contracts/src/District0xNetworkToken.sol): Main contract for DNT token. Derives MiniMeToken and VestedToken
- [MiniMeToken.sol](/resources/public/contracts/src/MiniMeToken.sol): Our slightly modified version of Giveth's [MiniMeToken](https://github.com/Giveth/minime)
- [VestedToken.sol](/resources/public/contracts/src/VestedToken.sol): Our slightly modified version of OpenZeppelin's [VestedToken](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/VestedToken.sol)
Contribution:
- [District0xContribution.sol](/resources/public/contracts/src/District0xContribution.sol): Implementation of our token sale
- [MultisigWallet.sol](/resources/public/contracts/src/District0xContribution.sol): Consensys multisig wallet used for district0x funds
## Tests
To run our smart-contract tests you need to have [node](https://nodejs.org/en/) installed on your machine.
Our tests are written in Clojurescript here [tests.cljs](/test/contribution/tests.cljs), but they are compiled into Javascript
here [contribution-tests.js](/contribution-tests.js), so you don't need to do that. You can just run tests with following commands:
```bash
npm install
node contribution-tests.js
```
================================================
FILE: compile-solidity.sh
================================================
#!/usr/bin/env bash
cd resources/public/contracts/src
#solc --overwrite --optimize --bin --abi District0xNetworkToken.sol -o ../build/
#solc --overwrite --optimize --bin --abi MultisigWallet.sol -o ../build/
#solc --overwrite --optimize --bin --abi District0xContribution.sol -o ../build/
solc --overwrite --optimize --bin --abi TokenVesting.sol -o ../build/
cd ../build
#wc -c District0xNetworkToken.bin | awk '{print "District0xNetworkToken: " $1}'
#wc -c District0xContribution.bin | awk '{print "District0xContribution: " $1}'
#wc -c MiniMeTokenFactory.bin | awk '{print "MiniMeTokenFactory: " $1}'
#wc -c MultisigWallet.bin | awk '{print "MultisigWallet: " $1}'
wc -c TokenVesting.bin | awk '{print "TokenVesting: " $1}'
================================================
FILE: docker-builds/ui/Dockerfile
================================================
FROM debian:stretch-slim
MAINTAINER "Filip Bielejec"
RUN apt-get update -y \
&& apt-get install --no-install-recommends -y \
-q wget nginx
# replace nginx config
COPY docker-builds/ui/nginx.conf /etc/nginx/nginx.conf
# replace default server
COPY docker-builds/ui/default /etc/nginx/sites-available/default
# nginx config
COPY docker-builds/ui/contribution.district0x.io /etc/nginx/sites-available/contribution.district0x.io
# setup error page
RUN wget --no-check-certificate -O X0X.html https://raw.githubusercontent.com/district0x/X0X/master/X0X.html \
&& mv X0X.html /usr/share/nginx/html/X0X.html
# setup static server
RUN ln -s -f /etc/nginx/sites-available/contribution.district0x.io /etc/nginx/sites-enabled/contribution.district0x.io
# get compiled JS
COPY resources/public /app/resources/public/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
================================================
FILE: docker-builds/ui/contribution.district0x.io
================================================
server {
listen 80 default_server;
root /app/resources/public/;
index index.html;
location / {
# add_header Cache-Control "no-store";
expires 1h;
add_header Cache-Control "public";
try_files $uri $uri/index.html /index.html;
}
location ~ /(contracts|images|assets|js|css|fonts)(.*)$ {
expires 1h;
add_header Cache-Control "public";
rewrite /(contracts|images|assets|js|css|fonts)(.*) /$1$2 break;
try_files $uri $uri/index.html /index.html;
}
location = /X0X.html {
root /usr/share/nginx/html/;
internal;
}
# redirect server error pages to the static error page
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 /X0X.html;
}
================================================
FILE: docker-builds/ui/default
================================================
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
# Default server configuration
#
# server {
# listen 80 default_server;
# listen [::]:80 default_server;
# # SSL configuration
# #
# # listen 443 ssl default_server;
# # listen [::]:443 ssl default_server;
# #
# # Note: You should disable gzip for SSL traffic.
# # See: https://bugs.debian.org/773332
# #
# # Read up on ssl_ciphers to ensure a secure configuration.
# # See: https://bugs.debian.org/765782
# #
# # Self signed certs generated by the ssl-cert package
# # Don't use them in a production server!
# #
# # include snippets/snakeoil.conf;
# root /var/www/html;
# # Add index.php to the list if you are using PHP
# index index.html index.htm index.nginx-debian.html;
# server_name _;
# location / {
# # First attempt to serve request as file, then
# # as directory, then fall back to displaying a 404.
# try_files $uri $uri/ =404;
# # proxy_pass http://localhost:8080;
# # proxy_http_version 1.1;
# # proxy_set_header Upgrade $http_upgrade;
# # proxy_set_header Connection 'upgrade';
# # proxy_set_header Host $host;
# # proxy_cache_bypass $http_upgrade;
# }
# # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
# #
# #location ~ \.php$ {
# # include snippets/fastcgi-php.conf;
# #
# # # With php7.0-cgi alone:
# # fastcgi_pass 127.0.0.1:9000;
# # # With php7.0-fpm:
# # fastcgi_pass unix:/run/php/php7.0-fpm.sock;
# #}
# # deny access to .htaccess files, if Apache's document root
# # concurs with nginx's one
# #
# #location ~ /\.ht {
# # deny all;
# #}
# }
# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
# listen 80;
# listen [::]:80;
#
# server_name example.com;
#
# root /var/www/example.com;
# index index.html;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
================================================
FILE: docker-builds/ui/nginx.conf
================================================
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
gzip_disable "MSIE [1-6]\.";
# gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
##
# user settings
##
server_names_hash_bucket_size 64;
# set client body size
client_max_body_size 10M;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
================================================
FILE: docker-push.sh
================================================
#!/bin/bash
#--- ARGS
BUILD_ENV=$1
#--- FUNCTIONS
function build {
{
NAME=$1
BUILD_ENV=$2
TAG=$(git log -1 --pretty=%h)
IMG=$NAME:$TAG
SERVICE=$(echo $NAME | cut -d "-" -f 2)
echo "============================================="
echo "["$BUILD_ENV"] ["$SERVICE"] Buidling: "$IMG""
echo "============================================="
lein less4j once
lein cljsbuild once "min"
docker build -t $IMG -f docker-builds/$SERVICE/Dockerfile .
case $BUILD_ENV in
# "qa")
# # qa images are tagged as `latest`
# docker tag $IMG $NAME:latest
# ;;
"prod")
# prod images are tagged as `release`
docker tag $IMG $NAME:release
;;
*)
echo "ERROR: don't know what to do with BUILD_ENV: "$BUILD_ENV""
exit 1
;;
esac
} || {
echo "EXCEPTION WHEN BUIDLING "$IMG""
exit 1
}
}
function push {
NAME=$1
echo "Pushing: " $NAME
docker push $NAME
}
function login {
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
}
function before {
lein deps
lein npm install
# lein compile-solidity
}
#--- EXECUTE
before
login
images=(
district0x/contribution-ui
)
for i in "${images[@]}"; do
(
build $i $BUILD_ENV
push $i
)
done # END: i loop
exit $?
================================================
FILE: project.clj
================================================
(defproject contribution "0.1.0-SNAPSHOT"
:description "Contribution period for district0x"
:url "http://contribution.district0x.io"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[cljs-react-material-ui "0.2.44"]
[cljs-web3 "0.19.0-0-5"]
[day8.re-frame/async-flow-fx "0.0.6"]
[district0x "0.1.19"]
[lein-doo "0.1.7"]
[madvas/reagent-patched "0.6.1" :exclusions [cljsjs/react cljsjs/react-dom]]
[medley "0.8.3"]
[org.clojure/clojurescript "1.9.671"]
[print-foo-cljs "2.0.3"]
[re-frame "0.9.4" :exclusions [reagent]]]
:plugins [[lein-auto "0.1.2"]
[lein-cljsbuild "1.1.4"]
[lein-shell "0.5.0"]
[deraen/lein-less4j "0.5.0"]
[lein-npm "0.6.2"]
[lein-doo "0.1.7"]]
:jvm-opts ["-Xss3m" "-XX:+TieredCompilation" "-XX:TieredStopAtLevel=1"]
:npm {:dependencies [[source-map-support "0.4.0"]
[web3 "0.19.0"]
[ws "2.0.1"]
[ethereumjs-testrpc "3.0.3"]
[solc "0.4.11"]]}
:min-lein-version "2.5.3"
:source-paths ["src/cljs"]
:clean-targets ^{:protect false} ["resources/public/js/compiled" "resources/public/css" "target"]
:figwheel {:server-port 6376}
:auto {"compile-solidity" {:file-pattern #"\.(sol)$"
:paths ["resources/public/contracts/src"]}}
:aliases {"compile-solidity" ["shell" "./compile-solidity.sh"]}
:less {:source-paths ["resources/public/less"]
:target-path "resources/public/css"
:target-dir "resources/public/css"
:source-map true
:compression true}
:profiles {:dev
{:dependencies [[org.clojure/clojure "1.8.0"]
[binaryage/devtools "0.9.4"]
[com.cemerick/piggieback "0.2.1"]
[figwheel-sidecar "0.5.10"]
[org.clojure/tools.nrepl "0.2.13"]]
:plugins [[lein-figwheel "0.5.10"]]
:source-paths []
:resource-paths ["resources"]
:cljsbuild {:builds [{:id "dev"
:source-paths ["src/cljs"]
:figwheel {:on-jsload "contribution.core/mount-root"}
:compiler {:main "contribution.core"
:output-to "resources/public/js/compiled/app.js"
:output-dir "resources/public/js/compiled/out"
:asset-path "js/compiled/out"
:source-map-timestamp true
:preloads [print.foo.preloads.devtools]
:closure-defines {goog.DEBUG true}
:external-config {:devtools/config {:features-to-install :all}}}}
{:id "min"
:source-paths ["src/cljs"]
:compiler {:main "contribution.core"
:output-to "resources/public/js/compiled/app.js"
:optimizations :advanced
:closure-defines {goog.DEBUG false}
:pretty-print false
:pseudo-names false}}
{:id "tests"
:source-paths ["src/cljs" "test"]
:figwheel true
:compiler {:main "contribution.cmd"
:output-to "tests/contribution-tests.js",
:output-dir "tests",
:target :nodejs,
:optimizations :none,
:verbose true
:source-map true}}]}}})
================================================
FILE: resources/public/contracts/build/ApproveAndCallFallBack.abi
================================================
[{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_token","type":"address"},{"name":"_data","type":"bytes"}],"name":"receiveApproval","outputs":[],"payable":false,"type":"function"}]
================================================
FILE: resources/public/contracts/build/ApproveAndCallReceiver.abi
================================================
[{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_token","type":"address"},{"name":"_data","type":"bytes"}],"name":"receiveApproval","outputs":[],"payable":false,"type":"function"}]
================================================
FILE: resources/public/contracts/build/BasicToken.abi
================================================
[{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
================================================
FILE: resources/public/contracts/build/Controlled.abi
================================================
[{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeController","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"controller","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]
================================================
FILE: resources/public/contracts/build/Controller.abi
================================================
[{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onApprove","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"proxyPayment","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"}]
================================================
FILE: resources/public/contracts/build/D0xToken.abi
================================================
[{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"},{"name":"_start","type":"uint64"},{"name":"_cliff","type":"uint64"},{"name":"_vesting","type":"uint64"}],"name":"grantVestedTokens","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_holder","type":"address"}],"name":"tokenGrantsCount","outputs":[{"name":"index","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"minter","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"grants","outputs":[{"name":"granter","type":"address"},{"name":"value","type":"uint256"},{"name":"cliff","type":"uint64"},{"name":"vesting","type":"uint64"},{"name":"start","type":"uint64"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_holder","type":"address"},{"name":"_grantId","type":"uint256"}],"name":"tokenGrant","outputs":[{"name":"granter","type":"address"},{"name":"value","type":"uint256"},{"name":"vested","type":"uint256"},{"name":"start","type":"uint64"},{"name":"cliff","type":"uint64"},{"name":"vesting","type":"uint64"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"createToken","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"}],"name":"lastTokenIsTransferableDate","outputs":[{"name":"date","type":"uint64"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"MAX_TOTAL_TOKEN_AMOUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"transfersEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"}],"name":"revokeAllTokenGrants","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"},{"name":"time","type":"uint64"}],"name":"transferableTokens","outputs":[{"name":"nonVested","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"tokens","type":"uint256"},{"name":"time","type":"uint256"},{"name":"start","type":"uint256"},{"name":"cliff","type":"uint256"},{"name":"vesting","type":"uint256"}],"name":"calculateVestedTokens","outputs":[{"name":"vestedTokens","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"},{"name":"_grantId","type":"uint256"}],"name":"revokeTokenGrant","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_enabled","type":"bool"}],"name":"enableTransfers","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_minter","type":"address"}],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
================================================
FILE: resources/public/contracts/build/District0xContribution.abi
================================================
[{"constant":true,"inputs":[],"name":"totalContributed","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_minContribAmount","type":"uint256"}],"name":"setMinContribAmount","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"advisers","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"founder1","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"EARLY_CONTRIBUTOR_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"tokenAddr","type":"address"}],"name":"reclaimToken","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"contributors","outputs":[{"name":"amount","type":"uint256"},{"name":"isCompensated","type":"bool"},{"name":"amountCompensated","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"COMMUNITY_ADVISERS_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_softCapAmount","type":"uint256"},{"name":"_afterSoftCapDuration","type":"uint256"},{"name":"_hardCapAmount","type":"uint256"},{"name":"_startTime","type":"uint256"},{"name":"_endTime","type":"uint256"}],"name":"setContribPeriod","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"ADVISER_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"softCapReached","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"endTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"claimTokensFromTokenDistrict0xNetworkToken","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"contributorAddress","type":"address"}],"name":"getContributor","outputs":[{"name":"","type":"uint256"},{"name":"","type":"bool"},{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"maxGasPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"ADVISER_STAKE2","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"contributorsKeys","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"TEAM_VESTING_CLIFF","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"EARLY_CONTRIBUTOR_VESTING_CLIFF","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"enableContribPeriod","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"minContribAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"afterSoftCapDuration","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"emergencyStop","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"isEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getConfiguration","outputs":[{"name":"","type":"bool"},{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"address"},{"name":"_advisers","type":"address[]"},{"name":"","type":"bool"},{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"FOUNDER2_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"CONTRIB_PERIOD2_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"stopped","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"startTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"contributor","type":"address"}],"name":"contributeWithAddress","outputs":[],"payable":true,"type":"function"},{"constant":true,"inputs":[],"name":"founder2","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"earlySponsor","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"CONTRIB_PERIOD3_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"release","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"multisigWallet","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"hardCapReached","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"enableDistrict0xNetworkTokenTransfers","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"tokenTransfersEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"offset","type":"uint256"},{"name":"limit","type":"uint256"}],"name":"getUncompensatedContributors","outputs":[{"name":"contributorIndexes","type":"uint256[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getNow","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"from_","type":"address"},{"name":"value_","type":"uint256"},{"name":"data_","type":"bytes"}],"name":"tokenFallback","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"kill","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"hardCapAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"isContribPeriodRunning","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_maxGasPrice","type":"uint256"}],"name":"setMaxGasPrice","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"contribute","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onApprove","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_district0xNetworkToken","type":"address"}],"name":"setDistrict0xNetworkToken","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"TEAM_VESTING_PERIOD","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"district0xNetworkToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getContribPeriod","outputs":[{"name":"boolValues","type":"bool[3]"},{"name":"uintValues","type":"uint256[8]"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"tokenAddr","type":"address"}],"name":"isTokenSaleToken","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"CONTRIB_PERIOD1_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"EARLY_CONTRIBUTOR_VESTING_PERIOD","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"proxyPayment","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"},{"constant":true,"inputs":[],"name":"softCapAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"FOUNDER1_STAKE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"offset","type":"uint256"},{"name":"limit","type":"uint256"}],"name":"compensateContributors","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_multisigWallet","type":"address"},{"name":"_founder1","type":"address"},{"name":"_founder2","type":"address"},{"name":"_earlySponsor","type":"address"},{"name":"_advisers","type":"address[]"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"totalContributed","type":"uint256"},{"indexed":true,"name":"contributor","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"contributorsCount","type":"uint256"}],"name":"onContribution","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"endTime","type":"uint256"}],"name":"onSoftCapReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"endTime","type":"uint256"}],"name":"onHardCapReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"contributor","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"onCompensated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"isStopped","type":"bool"}],"name":"onEmergencyChanged","type":"event"}]
================================================
FILE: resources/public/contracts/build/District0xNetworkToken.abi
================================================
[{"constant":true,"inputs":[{"name":"_holder","type":"address"}],"name":"tokenGrantsCount","outputs":[{"name":"index","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"creationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"grants","outputs":[{"name":"granter","type":"address"},{"name":"value","type":"uint256"},{"name":"cliff","type":"uint64"},{"name":"vesting","type":"uint64"},{"name":"start","type":"uint64"},{"name":"revokable","type":"bool"},{"name":"burnsOnRevoke","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeController","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_blockNumber","type":"uint256"}],"name":"balanceOfAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_holder","type":"address"},{"name":"_grantId","type":"uint256"}],"name":"tokenGrant","outputs":[{"name":"granter","type":"address"},{"name":"value","type":"uint256"},{"name":"vested","type":"uint256"},{"name":"start","type":"uint64"},{"name":"cliff","type":"uint64"},{"name":"vesting","type":"uint64"},{"name":"revokable","type":"bool"},{"name":"burnsOnRevoke","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_cloneTokenName","type":"string"},{"name":"_cloneDecimalUnits","type":"uint8"},{"name":"_cloneTokenSymbol","type":"string"},{"name":"_snapshotBlock","type":"uint256"},{"name":"_transfersEnabled","type":"bool"}],"name":"createCloneToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_claimer","type":"address"}],"name":"claimTokens","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"}],"name":"lastTokenIsTransferableDate","outputs":[{"name":"date","type":"uint64"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"parentToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"generateTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"grantsController","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"},{"name":"_start","type":"uint64"},{"name":"_cliff","type":"uint64"},{"name":"_vesting","type":"uint64"},{"name":"_revokable","type":"bool"},{"name":"_burnsOnRevoke","type":"bool"}],"name":"grantVestedTokens","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_blockNumber","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"transfersEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"parentSnapShotBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"}],"name":"revokeAllTokenGrants","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"},{"name":"time","type":"uint64"}],"name":"transferableTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"destroyTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"tokens","type":"uint256"},{"name":"time","type":"uint256"},{"name":"start","type":"uint256"},{"name":"cliff","type":"uint256"},{"name":"vesting","type":"uint256"}],"name":"calculateVestedTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeGrantsController","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"tokenFactory","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"},{"name":"_grantId","type":"uint256"}],"name":"revokeTokenGrant","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_transfersEnabled","type":"bool"}],"name":"enableTransfers","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"controller","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[{"name":"_controller","type":"address"},{"name":"_tokenFactory","type":"address"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"grantId","type":"uint256"}],"name":"NewTokenGrant","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_token","type":"address"},{"indexed":true,"name":"_claimer","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"ClaimedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cloneToken","type":"address"},{"indexed":false,"name":"_snapshotBlock","type":"uint256"}],"name":"NewCloneToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Approval","type":"event"}]
================================================
FILE: resources/public/contracts/build/ERC20.abi
================================================
[{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
================================================
FILE: resources/public/contracts/build/ERC20Basic.abi
================================================
[{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
================================================
FILE: resources/public/contracts/build/GrantsControlled.abi
================================================
[{"constant":true,"inputs":[],"name":"grantsController","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeGrantsController","outputs":[],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]
================================================
FILE: resources/public/contracts/build/HasNoTokens.abi
================================================
[{"constant":false,"inputs":[{"name":"tokenAddr","type":"address"}],"name":"reclaimToken","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"from_","type":"address"},{"name":"value_","type":"uint256"},{"name":"data_","type":"bytes"}],"name":"tokenFallback","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"district0xNetworkToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"tokenAddr","type":"address"}],"name":"isTokenSaleToken","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}]
================================================
FILE: resources/public/contracts/build/LimitedTransferToken.abi
================================================
[{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"},{"name":"time","type":"uint64"}],"name":"transferableTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
================================================
FILE: resources/public/contracts/build/MiniMeToken.abi
================================================
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"creationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeController","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_blockNumber","type":"uint256"}],"name":"balanceOfAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_cloneTokenName","type":"string"},{"name":"_cloneDecimalUnits","type":"uint8"},{"name":"_cloneTokenSymbol","type":"string"},{"name":"_snapshotBlock","type":"uint256"},{"name":"_transfersEnabled","type":"bool"}],"name":"createCloneToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_claimer","type":"address"}],"name":"claimTokens","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"parentToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"generateTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_blockNumber","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"transfersEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"parentSnapShotBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"destroyTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"tokenFactory","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_transfersEnabled","type":"bool"}],"name":"enableTransfers","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"controller","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[{"name":"_tokenFactory","type":"address"},{"name":"_parentToken","type":"address"},{"name":"_parentSnapShotBlock","type":"uint256"},{"name":"_tokenName","type":"string"},{"name":"_decimalUnits","type":"uint8"},{"name":"_tokenSymbol","type":"string"},{"name":"_transfersEnabled","type":"bool"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_token","type":"address"},{"indexed":true,"name":"_claimer","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"ClaimedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cloneToken","type":"address"},{"indexed":false,"name":"_snapshotBlock","type":"uint256"}],"name":"NewCloneToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Approval","type":"event"}]
================================================
FILE: resources/public/contracts/build/MiniMeTokenFactory.abi
================================================
[{"constant":false,"inputs":[{"name":"_parentToken","type":"address"},{"name":"_snapshotBlock","type":"uint256"},{"name":"_tokenName","type":"string"},{"name":"_decimalUnits","type":"uint8"},{"name":"_tokenSymbol","type":"string"},{"name":"_transfersEnabled","type":"bool"}],"name":"createCloneToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}]
================================================
FILE: resources/public/contracts/build/MultisigWallet.abi
================================================
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"owners","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"address"}],"name":"removeOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"revokeConfirmation","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"address"}],"name":"confirmations","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"pending","type":"bool"},{"name":"executed","type":"bool"}],"name":"getTransactionCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"address"}],"name":"addOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"isConfirmed","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"getConfirmationCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"transactions","outputs":[{"name":"destination","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"executed","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getOwners","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"from","type":"uint256"},{"name":"to","type":"uint256"},{"name":"pending","type":"bool"},{"name":"executed","type":"bool"}],"name":"getTransactionIds","outputs":[{"name":"_transactionIds","type":"uint256[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"getConfirmations","outputs":[{"name":"_confirmations","type":"address[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"transactionCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_required","type":"uint256"}],"name":"changeRequirement","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"confirmTransaction","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"destination","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"submitTransaction","outputs":[{"name":"transactionId","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"MAX_OWNER_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"required","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"address"},{"name":"newOwner","type":"address"}],"name":"replaceOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"transactionId","type":"uint256"}],"name":"executeTransaction","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_owners","type":"address[]"},{"name":"_required","type":"uint256"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"Confirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"Revocation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"Submission","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"Execution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"transactionId","type":"uint256"}],"name":"ExecutionFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"OwnerAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"OwnerRemoval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"required","type":"uint256"}],"name":"RequirementChange","type":"event"}]
================================================
FILE: resources/public/contracts/build/Ownable.abi
================================================
[{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]
================================================
FILE: resources/public/contracts/build/Pausable.abi
================================================
[{"constant":false,"inputs":[],"name":"emergencyStop","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"stopped","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"release","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"isStopped","type":"bool"}],"name":"onEmergencyChanged","type":"event"}]
================================================
FILE: resources/public/contracts/build/SafeMath.abi
================================================
[]
================================================
FILE: resources/public/contracts/build/Shareable.abi
================================================
[{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_operation","type":"bytes32"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_operation","type":"bytes32"},{"name":"_owner","type":"address"}],"name":"hasConfirmed","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"ownerIndex","type":"uint256"}],"name":"getOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"required","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"_owners","type":"address[]"},{"name":"_required","type":"uint256"}],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"operation","type":"bytes32"}],"name":"Confirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"operation","type":"bytes32"}],"name":"Revoke","type":"event"}]
================================================
FILE: resources/public/contracts/build/StandardToken.abi
================================================
[{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
================================================
FILE: resources/public/contracts/build/TokenController.abi
================================================
[{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onApprove","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"proxyPayment","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"}]
================================================
FILE: resources/public/contracts/build/TokenVesting.abi
================================================
[{"constant":true,"inputs":[],"name":"duration","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cliff","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"releasableAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"}],"name":"release","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"vestedAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"beneficiary","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"}],"name":"revoke","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"revocable","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"released","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"start","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"revoked","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_beneficiary","type":"address"},{"name":"_start","type":"uint256"},{"name":"_cliff","type":"uint256"},{"name":"_duration","type":"uint256"},{"name":"_revocable","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Released","type":"event"},{"anonymous":false,"inputs":[],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]
================================================
FILE: resources/public/contracts/build/VestedToken.abi
================================================
[{"constant":true,"inputs":[{"name":"_holder","type":"address"}],"name":"tokenGrantsCount","outputs":[{"name":"index","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"grants","outputs":[{"name":"granter","type":"address"},{"name":"value","type":"uint256"},{"name":"cliff","type":"uint64"},{"name":"vesting","type":"uint64"},{"name":"start","type":"uint64"},{"name":"revokable","type":"bool"},{"name":"burnsOnRevoke","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_holder","type":"address"},{"name":"_grantId","type":"uint256"}],"name":"tokenGrant","outputs":[{"name":"granter","type":"address"},{"name":"value","type":"uint256"},{"name":"vested","type":"uint256"},{"name":"start","type":"uint64"},{"name":"cliff","type":"uint64"},{"name":"vesting","type":"uint64"},{"name":"revokable","type":"bool"},{"name":"burnsOnRevoke","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"}],"name":"lastTokenIsTransferableDate","outputs":[{"name":"date","type":"uint64"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"grantsController","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"},{"name":"_start","type":"uint64"},{"name":"_cliff","type":"uint64"},{"name":"_vesting","type":"uint64"},{"name":"_revokable","type":"bool"},{"name":"_burnsOnRevoke","type":"bool"}],"name":"grantVestedTokens","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"}],"name":"revokeAllTokenGrants","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"holder","type":"address"},{"name":"time","type":"uint64"}],"name":"transferableTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"tokens","type":"uint256"},{"name":"time","type":"uint256"},{"name":"start","type":"uint256"},{"name":"cliff","type":"uint256"},{"name":"vesting","type":"uint256"}],"name":"calculateVestedTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeGrantsController","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"},{"name":"_grantId","type":"uint256"}],"name":"revokeTokenGrant","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"grantId","type":"uint256"}],"name":"NewTokenGrant","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
================================================
FILE: resources/public/contracts/src/District0xContribution.sol
================================================
pragma solidity ^0.4.11;
/*
Copyright 2017, Matus Lestan (district0x)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
import "./SafeMath.sol";
import "./District0xNetworkToken.sol";
import "./Ownable.sol";
import "./Pausable.sol";
import "./HasNoTokens.sol";
import "./minime_interface/TokenController.sol";
contract District0xContribution is Pausable, HasNoTokens, TokenController {
using SafeMath for uint;
District0xNetworkToken public district0xNetworkToken;
address public multisigWallet; // Wallet that receives all sale funds
address public founder1; // Wallet of founder 1
address public founder2; // Wallet of founder 2
address public earlySponsor; // Wallet of early sponsor
address[] public advisers; // 4 Wallets of advisors
uint public constant FOUNDER1_STAKE = 119000000 ether; // 119M DNT
uint public constant FOUNDER2_STAKE = 79000000 ether; // 79M DNT
uint public constant EARLY_CONTRIBUTOR_STAKE = 5000000 ether; // 5M DNT
uint public constant ADVISER_STAKE = 5000000 ether; // 5M DNT
uint public constant ADVISER_STAKE2 = 1000000 ether; // 1M DNT
uint public constant COMMUNITY_ADVISERS_STAKE = 5000000 ether; // 5M DNT
uint public constant CONTRIB_PERIOD1_STAKE = 600000000 ether; // 600M DNT
uint public constant CONTRIB_PERIOD2_STAKE = 140000000 ether; // 140M DNT
uint public constant CONTRIB_PERIOD3_STAKE = 40000000 ether; // 40M DNT
uint public minContribAmount = 0.01 ether; // 0.01 ether
uint public maxGasPrice = 50000000000; // 50 GWei
uint public constant TEAM_VESTING_CLIFF = 24 weeks; // 6 months vesting cliff for founders and advisors, except community advisors
uint public constant TEAM_VESTING_PERIOD = 96 weeks; // 2 years vesting period for founders and advisors, except community advisors
uint public constant EARLY_CONTRIBUTOR_VESTING_CLIFF = 12 weeks; // 3 months vesting cliff for early sponsor
uint public constant EARLY_CONTRIBUTOR_VESTING_PERIOD = 24 weeks; // 6 months vesting cliff for early sponsor
bool public tokenTransfersEnabled = false; // DNT token transfers will be enabled manually
// after first contribution period
// Can't be disabled back
struct Contributor {
uint amount; // Amount of ETH contributed by an address in given contribution period
bool isCompensated; // Whether this contributor received DNT token for ETH contribution
uint amountCompensated; // Amount of DNT received. Not really needed to store,
// but stored for accounting and security purposes
}
uint public softCapAmount; // Soft cap of contribution period in wei
uint public afterSoftCapDuration; // Number of seconds to the end of sale from the moment of reaching soft cap (unless reaching hardcap)
uint public hardCapAmount; // When reached this amount of wei, the contribution will end instantly
uint public startTime; // Start time of contribution period in UNIX time
uint public endTime; // End time of contribution period in UNIX time
bool public isEnabled; // If contribution period was enabled by multisignature
bool public softCapReached; // If soft cap was reached
bool public hardCapReached; // If hard cap was reached
uint public totalContributed; // Total amount of ETH contributed in given period
address[] public contributorsKeys; // Addresses of all contributors in given contribution period
mapping (address => Contributor) public contributors;
event onContribution(uint totalContributed, address indexed contributor, uint amount,
uint contributorsCount);
event onSoftCapReached(uint endTime);
event onHardCapReached(uint endTime);
event onCompensated(address indexed contributor, uint amount);
modifier onlyMultisig() {
require(multisigWallet == msg.sender);
_;
}
function District0xContribution(
address _multisigWallet,
address _founder1,
address _founder2,
address _earlySponsor,
address[] _advisers
) {
require(_advisers.length == 5);
multisigWallet = _multisigWallet;
founder1 = _founder1;
founder2 = _founder2;
earlySponsor = _earlySponsor;
advisers = _advisers;
}
// @notice Returns true if contribution period is currently running
function isContribPeriodRunning() constant returns (bool) {
return !hardCapReached &&
isEnabled &&
startTime <= now &&
endTime > now;
}
function contribute()
payable
stopInEmergency
{
contributeWithAddress(msg.sender);
}
// @notice Function to participate in contribution period
// Amounts from the same address should be added up
// If soft or hard cap is reached, end time should be modified
// Funds should be transferred into multisig wallet
// @param contributor Address that will receive DNT token
function contributeWithAddress(address contributor)
payable
stopInEmergency
{
require(tx.gasprice <= maxGasPrice);
require(msg.value >= minContribAmount);
require(isContribPeriodRunning());
uint contribValue = msg.value;
uint excessContribValue = 0;
uint oldTotalContributed = totalContributed;
totalContributed = oldTotalContributed.add(contribValue);
uint newTotalContributed = totalContributed;
// Soft cap was reached
if (newTotalContributed >= softCapAmount &&
oldTotalContributed < softCapAmount)
{
softCapReached = true;
endTime = afterSoftCapDuration.add(now);
onSoftCapReached(endTime);
}
// Hard cap was reached
if (newTotalContributed >= hardCapAmount &&
oldTotalContributed < hardCapAmount)
{
hardCapReached = true;
endTime = now;
onHardCapReached(endTime);
// Everything above hard cap will be sent back to contributor
excessContribValue = newTotalContributed.sub(hardCapAmount);
contribValue = contribValue.sub(excessContribValue);
totalContributed = hardCapAmount;
}
if (contributors[contributor].amount == 0) {
contributorsKeys.push(contributor);
}
contributors[contributor].amount = contributors[contributor].amount.add(contribValue);
multisigWallet.transfer(contribValue);
if (excessContribValue > 0) {
msg.sender.transfer(excessContribValue);
}
onContribution(newTotalContributed, contributor, contribValue, contributorsKeys.length);
}
// @notice This method is called by owner after contribution period ends, to distribute DNT in proportional manner
// Each contributor should receive DNT just once even if this method is called multiple times
// In case of many contributors must be able to compensate contributors in paginational way, otherwise might
// run out of gas if wanted to compensate all on one method call. Therefore parameters offset and limit
// @param periodIndex Index of contribution period (0-2)
// @param offset Number of first contributors to skip.
// @param limit Max number of contributors compensated on this call
function compensateContributors(uint offset, uint limit)
onlyOwner
{
require(isEnabled);
require(endTime < now);
uint i = offset;
uint compensatedCount = 0;
uint contributorsCount = contributorsKeys.length;
uint ratio = CONTRIB_PERIOD1_STAKE
.mul(1000000000000000000)
.div(totalContributed);
while (i < contributorsCount && compensatedCount < limit) {
address contributorAddress = contributorsKeys[i];
if (!contributors[contributorAddress].isCompensated) {
uint amountContributed = contributors[contributorAddress].amount;
contributors[contributorAddress].isCompensated = true;
contributors[contributorAddress].amountCompensated =
amountContributed.mul(ratio).div(1000000000000000000);
district0xNetworkToken.transfer(contributorAddress, contributors[contributorAddress].amountCompensated);
onCompensated(contributorAddress, contributors[contributorAddress].amountCompensated);
compensatedCount++;
}
i++;
}
}
// @notice Method for setting up contribution period
// Only owner should be able to execute
// Setting first contribution period sets up vesting for founders & advisors
// Contribution period should still not be enabled after calling this method
// @param softCapAmount Soft Cap in wei
// @param afterSoftCapDuration Number of seconds till the end of sale in the moment of reaching soft cap (unless reaching hard cap)
// @param hardCapAmount Hard Cap in wei
// @param startTime Contribution start time in UNIX time
// @param endTime Contribution end time in UNIX time
function setContribPeriod(
uint _softCapAmount,
uint _afterSoftCapDuration,
uint _hardCapAmount,
uint _startTime,
uint _endTime
)
onlyOwner
{
require(_softCapAmount > 0);
require(_hardCapAmount > _softCapAmount);
require(_afterSoftCapDuration > 0);
require(_startTime > now);
require(_endTime > _startTime);
require(!isEnabled);
softCapAmount = _softCapAmount;
afterSoftCapDuration = _afterSoftCapDuration;
hardCapAmount = _hardCapAmount;
startTime = _startTime;
endTime = _endTime;
district0xNetworkToken.revokeAllTokenGrants(founder1);
district0xNetworkToken.revokeAllTokenGrants(founder2);
district0xNetworkToken.revokeAllTokenGrants(earlySponsor);
for (uint j = 0; j < advisers.length; j++) {
district0xNetworkToken.revokeAllTokenGrants(advisers[j]);
}
uint64 vestingDate = uint64(startTime.add(TEAM_VESTING_PERIOD));
uint64 cliffDate = uint64(startTime.add(TEAM_VESTING_CLIFF));
uint64 earlyContribVestingDate = uint64(startTime.add(EARLY_CONTRIBUTOR_VESTING_PERIOD));
uint64 earlyContribCliffDate = uint64(startTime.add(EARLY_CONTRIBUTOR_VESTING_CLIFF));
uint64 startDate = uint64(startTime);
district0xNetworkToken.grantVestedTokens(founder1, FOUNDER1_STAKE, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(founder2, FOUNDER2_STAKE, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(earlySponsor, EARLY_CONTRIBUTOR_STAKE, startDate, earlyContribCliffDate, earlyContribVestingDate, true, false);
district0xNetworkToken.grantVestedTokens(advisers[0], ADVISER_STAKE, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(advisers[1], ADVISER_STAKE, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(advisers[2], ADVISER_STAKE2, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(advisers[3], ADVISER_STAKE2, startDate, cliffDate, vestingDate, true, false);
// Community advisors stake has no vesting, but we set it up this way, so we can revoke it in case of
// re-setting up contribution period
district0xNetworkToken.grantVestedTokens(advisers[4], COMMUNITY_ADVISERS_STAKE, startDate, startDate, startDate, true, false);
}
// @notice Enables contribution period
// Must be executed by multisignature
function enableContribPeriod()
onlyMultisig
{
require(startTime > now);
isEnabled = true;
}
// @notice Sets new min. contribution amount
// Only owner can execute
// Cannot be executed while contribution period is running
// @param _minContribAmount new min. amount
function setMinContribAmount(uint _minContribAmount)
onlyOwner
{
require(_minContribAmount > 0);
require(startTime > now);
minContribAmount = _minContribAmount;
}
// @notice Sets new max gas price for contribution
// Only owner can execute
// Cannot be executed while contribution period is running
// @param _minContribAmount new min. amount
function setMaxGasPrice(uint _maxGasPrice)
onlyOwner
{
require(_maxGasPrice > 0);
require(startTime > now);
maxGasPrice = _maxGasPrice;
}
// @notice Sets District0xNetworkToken contract
// Generates all DNT tokens and assigns them to this contract
// If token contract has already generated tokens, do not generate again
// @param _district0xNetworkToken District0xNetworkToken address
function setDistrict0xNetworkToken(address _district0xNetworkToken)
onlyOwner
{
require(_district0xNetworkToken != 0x0);
require(!isEnabled);
district0xNetworkToken = District0xNetworkToken(_district0xNetworkToken);
if (district0xNetworkToken.totalSupply() == 0) {
district0xNetworkToken.generateTokens(this, FOUNDER1_STAKE
.add(FOUNDER2_STAKE)
.add(EARLY_CONTRIBUTOR_STAKE)
.add(ADVISER_STAKE.mul(2))
.add(ADVISER_STAKE2.mul(2))
.add(COMMUNITY_ADVISERS_STAKE)
.add(CONTRIB_PERIOD1_STAKE));
district0xNetworkToken.generateTokens(multisigWallet, CONTRIB_PERIOD2_STAKE
.add(CONTRIB_PERIOD3_STAKE));
}
}
// @notice Enables transfers of DNT
// Will be executed after first contribution period by owner
function enableDistrict0xNetworkTokenTransfers()
onlyOwner
{
require(endTime < now);
tokenTransfersEnabled = true;
}
// @notice Method to claim tokens accidentally sent to a DNT contract
// Only multisig wallet can execute
// @param _token Address of claimed ERC20 Token
function claimTokensFromTokenDistrict0xNetworkToken(address _token)
onlyMultisig
{
district0xNetworkToken.claimTokens(_token, multisigWallet);
}
// @notice Kill method should not really be needed, but just in case
function kill(address _to) onlyMultisig external {
suicide(_to);
}
function()
payable
stopInEmergency
{
contributeWithAddress(msg.sender);
}
// MiniMe Controller default settings for allowing token transfers.
function proxyPayment(address _owner) payable public returns (bool) {
throw;
}
// Before transfers are enabled for everyone, only this contract is allowed to distribute DNT
function onTransfer(address _from, address _to, uint _amount) public returns (bool) {
return tokenTransfersEnabled || _from == address(this) || _to == address(this);
}
function onApprove(address _owner, address _spender, uint _amount) public returns (bool) {
return tokenTransfersEnabled;
}
function isTokenSaleToken(address tokenAddr) returns(bool) {
return district0xNetworkToken == tokenAddr;
}
/*
Following constant methods are used for tests and contribution web app
They don't impact logic of contribution contract, therefor DOES NOT NEED TO BE AUDITED
*/
// Used by contribution front-end to obtain contribution period properties
function getContribPeriod()
constant
returns (bool[3] boolValues, uint[8] uintValues)
{
boolValues[0] = isEnabled;
boolValues[1] = softCapReached;
boolValues[2] = hardCapReached;
uintValues[0] = softCapAmount;
uintValues[1] = afterSoftCapDuration;
uintValues[2] = hardCapAmount;
uintValues[3] = startTime;
uintValues[4] = endTime;
uintValues[5] = totalContributed;
uintValues[6] = contributorsKeys.length;
uintValues[7] = CONTRIB_PERIOD1_STAKE;
return (boolValues, uintValues);
}
// Used by contribution front-end to obtain contribution contract properties
function getConfiguration()
constant
returns (bool, address, address, address, address, address[] _advisers, bool, uint)
{
_advisers = new address[](advisers.length);
for (uint i = 0; i < advisers.length; i++) {
_advisers[i] = advisers[i];
}
return (stopped, multisigWallet, founder1, founder2, earlySponsor, _advisers, tokenTransfersEnabled,
maxGasPrice);
}
// Used by contribution front-end to obtain contributor's properties
function getContributor(address contributorAddress)
constant
returns(uint, bool, uint)
{
Contributor contributor = contributors[contributorAddress];
return (contributor.amount, contributor.isCompensated, contributor.amountCompensated);
}
// Function to verify if all contributors were compensated
function getUncompensatedContributors(uint offset, uint limit)
constant
returns (uint[] contributorIndexes)
{
uint contributorsCount = contributorsKeys.length;
if (limit == 0) {
limit = contributorsCount;
}
uint i = offset;
uint resultsCount = 0;
uint[] memory _contributorIndexes = new uint[](limit);
while (i < contributorsCount && resultsCount < limit) {
if (!contributors[contributorsKeys[i]].isCompensated) {
_contributorIndexes[resultsCount] = i;
resultsCount++;
}
i++;
}
contributorIndexes = new uint[](resultsCount);
for (i = 0; i < resultsCount; i++) {
contributorIndexes[i] = _contributorIndexes[i];
}
return contributorIndexes;
}
function getNow()
constant
returns(uint)
{
return now;
}
}
================================================
FILE: resources/public/contracts/src/District0xNetworkToken.sol
================================================
pragma solidity ^0.4.11;
import "./MiniMeToken.sol";
import "./VestedToken.sol";
contract District0xNetworkToken is MiniMeToken, VestedToken {
function District0xNetworkToken(address _controller, address _tokenFactory)
MiniMeToken(
_tokenFactory,
0x0, // no parent token
0, // no snapshot block number from parent
"district0x Network Token", // Token name
18, // Decimals
"DNT", // Symbol
true // Enable transfers
)
{
changeController(_controller);
changeGrantsController(_controller);
}
}
================================================
FILE: resources/public/contracts/src/ERC20.sol
================================================
pragma solidity ^0.4.11;
import './ERC20Basic.sol';
/*
* ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*
* Slightly modified version of OpenZeppelin's ERC20
* Original can be found ./orig/ERC20.sol or https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/ERC20.sol
* Modifications:
* - Added doTransfer so it can be used in VestedToken with implmentation from MiniMe token
*
*/
contract ERC20 is ERC20Basic {
mapping(address => uint) balances;
function allowance(address owner, address spender) constant returns (uint);
function transferFrom(address from, address to, uint value) returns (bool);
function approve(address spender, uint value) returns (bool);
function approveAndCall(address spender, uint256 value, bytes extraData) returns (bool);
event Approval(address indexed owner, address indexed spender, uint value);
function doTransfer(address _from, address _to, uint _amount) internal returns(bool);
}
================================================
FILE: resources/public/contracts/src/ERC20Basic.sol
================================================
pragma solidity ^0.4.11;
/*
* ERC20Basic
* Simpler version of ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20Basic {
function totalSupply() constant returns (uint);
function balanceOf(address who) constant returns (uint);
function transfer(address to, uint value) returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
}
================================================
FILE: resources/public/contracts/src/GrantsControlled.sol
================================================
pragma solidity ^0.4.11;
/*
This contract adds modifier to VestedToken contract in order to restrict creating
vesting on to contribution contract for security purposes.
*/
contract GrantsControlled {
modifier onlyGrantsController { if (msg.sender != grantsController) throw; _; }
address public grantsController;
function GrantsControlled() { grantsController = msg.sender;}
function changeGrantsController(address _newController) onlyGrantsController {
grantsController = _newController;
}
}
================================================
FILE: resources/public/contracts/src/HasNoTokens.sol
================================================
pragma solidity ^0.4.11;
import "./ERC20Basic.sol";
import "./Ownable.sol";
import "./District0xNetworkToken.sol";
/**
* @title Contracts that should not own Tokens
* @author Remco Bloemen
* @dev This blocks incoming ERC23 tokens to prevent accidental loss of tokens.
* Should tokens (any ERC20Basic compatible) end up in the contract, it allows the
* owner to reclaim the tokens.
*/
contract HasNoTokens is Ownable {
District0xNetworkToken public district0xNetworkToken;
/**
* @dev Reject all ERC23 compatible tokens
* @param from_ address The address that is transferring the tokens
* @param value_ uint256 the amount of the specified token
* @param data_ Bytes The data passed from the caller.
*/
function tokenFallback(address from_, uint256 value_, bytes data_) external {
throw;
}
function isTokenSaleToken(address tokenAddr) returns(bool);
/**
* @dev Reclaim all ERC20Basic compatible tokens
* @param tokenAddr address The address of the token contract
*/
function reclaimToken(address tokenAddr) external onlyOwner {
require(!isTokenSaleToken(tokenAddr));
ERC20Basic tokenInst = ERC20Basic(tokenAddr);
uint256 balance = tokenInst.balanceOf(this);
tokenInst.transfer(msg.sender, balance);
}
}
================================================
FILE: resources/public/contracts/src/LimitedTransferToken.sol
================================================
pragma solidity ^0.4.11;
import "./ERC20.sol";
/*
Very slightly modified version of OpenZeppelin's LimitedTransferToken
Original can be found at ./orig/LimitedTransferToken.sol or https://raw.githubusercontent.com/OpenZeppelin/zeppelin-solidity/master/contracts/token/LimitedTransferToken.sol
Modifications:
- Added return types "bool" so it's compact with MiniMeToken
*/
contract LimitedTransferToken is ERC20 {
// Checks whether it can transfer or otherwise throws.
modifier canTransfer(address _sender, uint _value) {
if (_value > transferableTokens(_sender, uint64(now))) throw;
_;
}
// Checks modifier and allows transfer if tokens are not locked.
function transfer(address _to, uint _value) canTransfer(msg.sender, _value) returns (bool) {
return super.transfer(_to, _value);
}
// Checks modifier and allows transfer if tokens are not locked.
function transferFrom(address _from, address _to, uint _value) canTransfer(_from, _value) returns (bool) {
return super.transferFrom(_from, _to, _value);
}
// Default transferable tokens function returns all tokens for a holder (no limit).
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
return balanceOf(holder);
}
}
================================================
FILE: resources/public/contracts/src/MiniMeToken.sol
================================================
pragma solidity ^0.4.11;
import "./minime_interface/Controlled.sol";
import "./minime_interface/TokenController.sol";
import "./minime_interface/ApproveAndCallFallback.sol";
import "./ERC20.sol";
import "./SafeMath.sol";
import "./ERC20Basic.sol";
/*
Slightly modified version of Giveth's MiniMeToken
Original can be found at ./orig/MiniMeToken.sol or https://github.com/Giveth/minime
Modifications:
- Split contracts into multiple files
- Use SafeMath.sol
- Make it descendant of ERC20
*/
/// @dev The actual token contract, the default controller is the msg.sender
/// that deploys the contract, so usually this token will be deployed by a
/// token controller contract, which Giveth will call a "Campaign"
contract MiniMeToken is ERC20, Controlled {
using SafeMath for uint;
string public name; //The Token's name: e.g. DigixDAO Tokens
uint8 public decimals; //Number of decimals of the smallest unit
string public symbol; //An identifier: e.g. REP
string public version = 'MMT_0.1'; //An arbitrary versioning scheme
/// @dev `Checkpoint` is the structure that attaches a block number to a
/// given value, the block number attached is the one that last changed the
/// value
struct Checkpoint {
// `fromBlock` is the block number that the value was generated from
uint128 fromBlock;
// `value` is the amount of tokens at a specific block number
uint128 value;
}
// `parentToken` is the Token address that was cloned to produce this token;
// it will be 0x0 for a token that was not cloned
MiniMeToken public parentToken;
// `parentSnapShotBlock` is the block number from the Parent Token that was
// used to determine the initial distribution of the Clone Token
uint public parentSnapShotBlock;
// `creationBlock` is the block number that the Clone Token was created
uint public creationBlock;
// `balances` is the map that tracks the balance of each address, in this
// contract when the balance changes the block number that the change
// occurred is also included in the map
mapping (address => Checkpoint[]) balances;
// `allowed` tracks any extra transfer rights as in all ERC20 tokens
mapping (address => mapping (address => uint256)) allowed;
// Tracks the history of the `totalSupply` of the token
Checkpoint[] totalSupplyHistory;
// Flag that determines if the token is transferable or not.
bool public transfersEnabled;
// The factory used to create new clone tokens
MiniMeTokenFactory public tokenFactory;
////////////////
// Constructor
////////////////
/// @notice Constructor to create a MiniMeToken
/// @param _tokenFactory The address of the MiniMeTokenFactory contract that
/// will create the Clone token contracts, the token factory needs to be
/// deployed first
/// @param _parentToken Address of the parent token, set to 0x0 if it is a
/// new token
/// @param _parentSnapShotBlock Block of the parent token that will
/// determine the initial distribution of the clone token, set to 0 if it
/// is a new token
/// @param _tokenName Name of the new token
/// @param _decimalUnits Number of decimals of the new token
/// @param _tokenSymbol Token Symbol for the new token
/// @param _transfersEnabled If true, tokens will be able to be transferred
function MiniMeToken(
address _tokenFactory,
address _parentToken,
uint _parentSnapShotBlock,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
bool _transfersEnabled
) {
tokenFactory = MiniMeTokenFactory(_tokenFactory);
name = _tokenName; // Set the name
decimals = _decimalUnits; // Set the decimals
symbol = _tokenSymbol; // Set the symbol
parentToken = MiniMeToken(_parentToken);
parentSnapShotBlock = _parentSnapShotBlock;
transfersEnabled = _transfersEnabled;
creationBlock = block.number;
}
///////////////////
// ERC20 Methods
///////////////////
/// @notice Send `_amount` tokens to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint256 _amount) returns (bool success) {
if (!transfersEnabled) throw;
return doTransfer(msg.sender, _to, _amount);
}
/// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
/// is approved by `_from`
/// @param _from The address holding the tokens being transferred
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return True if the transfer was successful
function transferFrom(address _from, address _to, uint256 _amount
) returns (bool success) {
// The controller of this contract can move tokens around at will,
// this is important to recognize! Confirm that you trust the
// controller of this contract, which in most situations should be
// another open source smart contract or 0x0
if (msg.sender != controller) {
if (!transfersEnabled) throw;
// The standard ERC 20 transferFrom functionality
if (allowed[_from][msg.sender] < _amount) return false;
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_amount);
}
return doTransfer(_from, _to, _amount);
}
/// @dev This is the actual transfer function in the token contract, it can
/// only be called by other functions in this contract.
/// @param _from The address holding the tokens being transferred
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return True if the transfer was successful
function doTransfer(address _from, address _to, uint _amount
) internal returns(bool) {
if (_amount == 0) {
return true;
}
if (parentSnapShotBlock >= block.number) throw;
// Do not allow transfer to 0x0 or the token contract itself
if ((_to == 0) || (_to == address(this))) throw;
// If the amount being transfered is more than the balance of the
// account the transfer returns false
var previousBalanceFrom = balanceOfAt(_from, block.number);
if (previousBalanceFrom < _amount) {
return false;
}
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
throw;
}
// First update the balance array with the new value for the address
// sending the tokens
updateValueAtNow(balances[_from], previousBalanceFrom.sub(_amount));
// Then update the balance array with the new value for the address
// receiving the tokens
var previousBalanceTo = balanceOfAt(_to, block.number);
updateValueAtNow(balances[_to], previousBalanceTo.add(_amount));
// An event to make the transfer easy to find on the blockchain
Transfer(_from, _to, _amount);
return true;
}
/// @param _owner The address that's balance is being requested
/// @return The balance of `_owner` at the current block
function balanceOf(address _owner) constant returns (uint256 balance) {
return balanceOfAt(_owner, block.number);
}
/// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
/// its behalf. This is a modified version of the ERC20 approve function
/// to be a little bit safer
/// @param _spender The address of the account able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the approval was successful
function approve(address _spender, uint256 _amount) returns (bool success) {
if (!transfersEnabled) throw;
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender,0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
if ((_amount!=0) && (allowed[msg.sender][_spender] !=0)) throw;
// Alerts the token controller of the approve function call
if (isContract(controller)) {
if (!TokenController(controller).onApprove(msg.sender, _spender, _amount))
throw;
}
allowed[msg.sender][_spender] = _amount;
Approval(msg.sender, _spender, _amount);
return true;
}
/// @dev This function makes it easy to read the `allowed[]` map
/// @param _owner The address of the account that owns the token
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens of _owner that _spender is allowed
/// to spend
function allowance(address _owner, address _spender
) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
/// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
/// its behalf, and then a function is triggered in the contract that is
/// being approved, `_spender`. This allows users to use their tokens to
/// interact with contracts in one function call instead of two
/// @param _spender The address of the contract able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the function call was successful
function approveAndCall(address _spender, uint256 _amount, bytes _extraData
) returns (bool success) {
if (!approve(_spender, _amount)) throw;
ApproveAndCallFallBack(_spender).receiveApproval(
msg.sender,
_amount,
this,
_extraData
);
return true;
}
/// @dev This function makes it easy to get the total number of tokens
/// @return The total number of tokens
function totalSupply() constant returns (uint) {
return totalSupplyAt(block.number);
}
////////////////
// Query balance and totalSupply in History
////////////////
/// @dev Queries the balance of `_owner` at a specific `_blockNumber`
/// @param _owner The address from which the balance will be retrieved
/// @param _blockNumber The block number when the balance is queried
/// @return The balance at `_blockNumber`
function balanceOfAt(address _owner, uint _blockNumber) constant
returns (uint) {
// These next few lines are used when the balance of the token is
// requested before a check point was ever created for this token, it
// requires that the `parentToken.balanceOfAt` be queried at the
// genesis block for that token as this contains initial balance of
// this token
if ((balances[_owner].length == 0)
|| (balances[_owner][0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
} else {
// Has no parent
return 0;
}
// This will return the expected balance during normal situations
} else {
return getValueAt(balances[_owner], _blockNumber);
}
}
/// @notice Total amount of tokens at a specific `_blockNumber`.
/// @param _blockNumber The block number when the totalSupply is queried
/// @return The total amount of tokens at `_blockNumber`
function totalSupplyAt(uint _blockNumber) constant returns(uint) {
// These next few lines are used when the totalSupply of the token is
// requested before a check point was ever created for this token, it
// requires that the `parentToken.totalSupplyAt` be queried at the
// genesis block for this token as that contains totalSupply of this
// token at this block number.
if ((totalSupplyHistory.length == 0)
|| (totalSupplyHistory[0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
} else {
return 0;
}
// This will return the expected totalSupply during normal situations
} else {
return getValueAt(totalSupplyHistory, _blockNumber);
}
}
////////////////
// Clone Token Method
////////////////
/// @notice Creates a new clone token with the initial distribution being
/// this token at `_snapshotBlock`
/// @param _cloneTokenName Name of the clone token
/// @param _cloneDecimalUnits Number of decimals of the smallest unit
/// @param _cloneTokenSymbol Symbol of the clone token
/// @param _snapshotBlock Block when the distribution of the parent token is
/// copied to set the initial distribution of the new clone token;
/// if the block is zero than the actual block, the current block is used
/// @param _transfersEnabled True if transfers are allowed in the clone
/// @return The address of the new MiniMeToken Contract
function createCloneToken(
string _cloneTokenName,
uint8 _cloneDecimalUnits,
string _cloneTokenSymbol,
uint _snapshotBlock,
bool _transfersEnabled
) returns(address) {
if (_snapshotBlock == 0) _snapshotBlock = block.number;
MiniMeToken cloneToken = tokenFactory.createCloneToken(
this,
_snapshotBlock,
_cloneTokenName,
_cloneDecimalUnits,
_cloneTokenSymbol,
_transfersEnabled
);
cloneToken.changeController(msg.sender);
// An event to make the token easy to find on the blockchain
NewCloneToken(address(cloneToken), _snapshotBlock);
return address(cloneToken);
}
////////////////
// Generate and destroy tokens
////////////////
/// @notice Generates `_amount` tokens that are assigned to `_owner`
/// @param _owner The address that will be assigned the new tokens
/// @param _amount The quantity of tokens generated
/// @return True if the tokens are generated correctly
function generateTokens(address _owner, uint _amount
) onlyController returns (bool) {
uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
updateValueAtNow(totalSupplyHistory, curTotalSupply.add(_amount));
var previousBalanceTo = balanceOf(_owner);
updateValueAtNow(balances[_owner], previousBalanceTo.add(_amount));
Transfer(0, _owner, _amount);
return true;
}
/// @notice Burns `_amount` tokens from `_owner`
/// @param _owner The address that will lose the tokens
/// @param _amount The quantity of tokens to burn
/// @return True if the tokens are burned correctly
function destroyTokens(address _owner, uint _amount
) onlyController returns (bool) {
uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
if (curTotalSupply < _amount) throw;
updateValueAtNow(totalSupplyHistory, curTotalSupply.sub(_amount));
var previousBalanceFrom = balanceOf(_owner);
if (previousBalanceFrom < _amount) throw;
updateValueAtNow(balances[_owner], previousBalanceFrom.sub(_amount));
Transfer(_owner, 0, _amount);
return true;
}
////////////////
// Enable tokens transfers
////////////////
/// @notice Enables token holders to transfer their tokens freely if true
/// @param _transfersEnabled True if transfers are allowed in the clone
function enableTransfers(bool _transfersEnabled) onlyController {
transfersEnabled = _transfersEnabled;
}
////////////////
// Internal helper functions to query and set a value in a snapshot array
////////////////
/// @dev `getValueAt` retrieves the number of tokens at a given block number
/// @param checkpoints The history of values being queried
/// @param _block The block number to retrieve the value at
/// @return The number of tokens being queried
function getValueAt(Checkpoint[] storage checkpoints, uint _block
) constant internal returns (uint) {
if (checkpoints.length == 0) return 0;
// Shortcut for the actual value
if (_block >= checkpoints[checkpoints.length-1].fromBlock)
return checkpoints[checkpoints.length-1].value;
if (_block < checkpoints[0].fromBlock) return 0;
// Binary search of the value in the array
uint min = 0;
uint max = checkpoints.length-1;
while (max > min) {
uint mid = (max + min + 1)/ 2;
if (checkpoints[mid].fromBlock<=_block) {
min = mid;
} else {
max = mid-1;
}
}
return checkpoints[min].value;
}
/// @dev `updateValueAtNow` used to update the `balances` map and the
/// `totalSupplyHistory`
/// @param checkpoints The history of data being updated
/// @param _value The new number of tokens
function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value
) internal {
if ((checkpoints.length == 0)
|| (checkpoints[checkpoints.length -1].fromBlock < block.number)) {
Checkpoint newCheckPoint = checkpoints[ checkpoints.length++ ];
newCheckPoint.fromBlock = uint128(block.number);
newCheckPoint.value = uint128(_value);
} else {
Checkpoint oldCheckPoint = checkpoints[checkpoints.length-1];
oldCheckPoint.value = uint128(_value);
}
}
/// @dev Internal function to determine if an address is a contract
/// @param _addr The address being queried
/// @return True if `_addr` is a contract
function isContract(address _addr) constant internal returns(bool) {
uint size;
if (_addr == 0) return false;
assembly {
size := extcodesize(_addr)
}
return size>0;
}
/// @dev Helper function to return a min betwen the two uints
function min(uint a, uint b) internal returns (uint) {
return a < b ? a : b;
}
/// @notice The fallback function: If the contract's controller has not been
/// set to 0, then the `proxyPayment` method is called which relays the
/// ether and creates tokens as described in the token controller contract
function () payable {
if (isContract(controller)) {
if (! TokenController(controller).proxyPayment.value(msg.value)(msg.sender))
throw;
} else {
throw;
}
}
//////////
// Safety Methods
//////////
/// @notice This method can be used by the controller to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0 in case you want to extract ether.
/// @param _claimer Address that tokens will be send to
function claimTokens(address _token, address _claimer) onlyController {
if (_token == 0x0) {
_claimer.transfer(this.balance);
return;
}
ERC20Basic token = ERC20Basic(_token);
uint balance = token.balanceOf(this);
token.transfer(_claimer, balance);
ClaimedTokens(_token, _claimer, balance);
}
////////////////
// Events
////////////////
event ClaimedTokens(address indexed _token, address indexed _claimer, uint _amount);
event Transfer(address indexed _from, address indexed _to, uint256 _amount);
event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _amount
);
}
////////////////
// MiniMeTokenFactory
////////////////
/// @dev This contract is used to generate clone contracts from a contract.
/// In solidity this is the way to create a contract from a contract of the
/// same class
contract MiniMeTokenFactory {
/// @notice Update the DApp by creating a new token with new functionalities
/// the msg.sender becomes the controller of this clone token
/// @param _parentToken Address of the token being cloned
/// @param _snapshotBlock Block of the parent token that will
/// determine the initial distribution of the clone token
/// @param _tokenName Name of the new token
/// @param _decimalUnits Number of decimals of the new token
/// @param _tokenSymbol Token Symbol for the new token
/// @param _transfersEnabled If true, tokens will be able to be transferred
/// @return The address of the new token contract
function createCloneToken(
address _parentToken,
uint _snapshotBlock,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
bool _transfersEnabled
) returns (MiniMeToken) {
MiniMeToken newToken = new MiniMeToken(
this,
_parentToken,
_snapshotBlock,
_tokenName,
_decimalUnits,
_tokenSymbol,
_transfersEnabled
);
newToken.changeController(msg.sender);
return newToken;
}
}
================================================
FILE: resources/public/contracts/src/MultisigWallet.sol
================================================
pragma solidity ^0.4.11;
/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
/// @author Stefan George -
contract MultiSigWallet {
uint constant public MAX_OWNER_COUNT = 50;
event Confirmation(address indexed sender, uint indexed transactionId);
event Revocation(address indexed sender, uint indexed transactionId);
event Submission(uint indexed transactionId);
event Execution(uint indexed transactionId);
event ExecutionFailure(uint indexed transactionId);
event Deposit(address indexed sender, uint value);
event OwnerAddition(address indexed owner);
event OwnerRemoval(address indexed owner);
event RequirementChange(uint required);
mapping (uint => Transaction) public transactions;
mapping (uint => mapping (address => bool)) public confirmations;
mapping (address => bool) public isOwner;
address[] public owners;
uint public required;
uint public transactionCount;
struct Transaction {
address destination;
uint value;
bytes data;
bool executed;
}
modifier onlyWallet() {
if (msg.sender != address(this))
throw;
_;
}
modifier ownerDoesNotExist(address owner) {
if (isOwner[owner])
throw;
_;
}
modifier ownerExists(address owner) {
if (!isOwner[owner])
throw;
_;
}
modifier transactionExists(uint transactionId) {
if (transactions[transactionId].destination == 0)
throw;
_;
}
modifier confirmed(uint transactionId, address owner) {
if (!confirmations[transactionId][owner])
throw;
_;
}
modifier notConfirmed(uint transactionId, address owner) {
if (confirmations[transactionId][owner])
throw;
_;
}
modifier notExecuted(uint transactionId) {
if (transactions[transactionId].executed)
throw;
_;
}
modifier notNull(address _address) {
if (_address == 0)
throw;
_;
}
modifier validRequirement(uint ownerCount, uint _required) {
if ( ownerCount > MAX_OWNER_COUNT
|| _required > ownerCount
|| _required == 0
|| ownerCount == 0)
throw;
_;
}
/// @dev Fallback function allows to deposit ether.
function()
payable
{
if (msg.value > 0)
Deposit(msg.sender, msg.value);
}
/*
* Public functions
*/
/// @dev Contract constructor sets initial owners and required number of confirmations.
/// @param _owners List of initial owners.
/// @param _required Number of required confirmations.
function MultiSigWallet(address[] _owners, uint _required)
public
validRequirement(_owners.length, _required)
{
for (uint i=0; i<_owners.length; i++) {
if (isOwner[_owners[i]] || _owners[i] == 0)
throw;
isOwner[_owners[i]] = true;
}
owners = _owners;
required = _required;
}
/// @dev Allows to add a new owner. Transaction has to be sent by wallet.
/// @param owner Address of new owner.
function addOwner(address owner)
public
onlyWallet
ownerDoesNotExist(owner)
notNull(owner)
validRequirement(owners.length + 1, required)
{
isOwner[owner] = true;
owners.push(owner);
OwnerAddition(owner);
}
/// @dev Allows to remove an owner. Transaction has to be sent by wallet.
/// @param owner Address of owner.
function removeOwner(address owner)
public
onlyWallet
ownerExists(owner)
{
isOwner[owner] = false;
for (uint i=0; i owners.length)
changeRequirement(owners.length);
OwnerRemoval(owner);
}
/// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
/// @param owner Address of owner to be replaced.
/// @param owner Address of new owner.
function replaceOwner(address owner, address newOwner)
public
onlyWallet
ownerExists(owner)
ownerDoesNotExist(newOwner)
{
for (uint i=0; i 0); // Solidity automatically throws when dividing by 0
uint c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint a, uint b) internal returns (uint) {
assert(b <= a);
return a - b;
}
function add(uint a, uint b) internal returns (uint) {
uint c = a + b;
assert(c >= a);
return c;
}
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
return a < b ? a : b;
}
function assert(bool assertion) internal {
if (!assertion) {
throw;
}
}
}
================================================
FILE: resources/public/contracts/src/Shareable.sol
================================================
pragma solidity ^0.4.11;
/*
* Shareable
*
* Based on https://github.com/ethereum/dapp-bin/blob/master/wallet/wallet.sol
*
* inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a single, or, crucially, each of a number of, designated owners.
*
* usage:
* use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by some number (specified in constructor) of the set of owners (specified in the constructor) before the interior is executed.
* Made by OpenZeppelin https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/ownership/Shareable.sol
*/
contract Shareable {
// struct for the status of a pending operation.
struct PendingState {
uint yetNeeded;
uint ownersDone;
uint index;
}
// the number of owners that must confirm the same operation before it is run.
uint public required;
// list of owners
address[256] owners;
// index on the list of owners to allow reverse lookup
mapping(address => uint) ownerIndex;
// the ongoing operations.
mapping(bytes32 => PendingState) pendings;
bytes32[] pendingsIndex;
// this contract only has six types of events: it can accept a confirmation, in which case
// we record owner and operation (hash) alongside it.
event Confirmation(address owner, bytes32 operation);
event Revoke(address owner, bytes32 operation);
// simple single-sig function modifier.
modifier onlyOwner {
if (!isOwner(msg.sender)) {
throw;
}
_;
}
// multi-sig function modifier: the operation must have an intrinsic hash in order
// that later attempts can be realised as the same underlying operation and
// thus count as confirmations.
modifier onlymanyowners(bytes32 _operation) {
if (confirmAndCheck(_operation)) {
_;
}
}
// constructor is given number of sigs required to do protected "onlymanyowners" transactions
// as well as the selection of addresses capable of confirming them.
function Shareable(address[] _owners, uint _required) {
owners[1] = msg.sender;
ownerIndex[msg.sender] = 1;
for (uint i = 0; i < _owners.length; ++i) {
owners[2 + i] = _owners[i];
ownerIndex[_owners[i]] = 2 + i;
}
required = _required;
if (required > owners.length) {
throw;
}
}
// Revokes a prior confirmation of the given operation
function revoke(bytes32 _operation) external {
uint index = ownerIndex[msg.sender];
// make sure they're an owner
if (index == 0) {
return;
}
uint ownerIndexBit = 2**index;
var pending = pendings[_operation];
if (pending.ownersDone & ownerIndexBit > 0) {
pending.yetNeeded++;
pending.ownersDone -= ownerIndexBit;
Revoke(msg.sender, _operation);
}
}
// Gets an owner by 0-indexed position (using numOwners as the count)
function getOwner(uint ownerIndex) external constant returns (address) {
return address(owners[ownerIndex + 1]);
}
function isOwner(address _addr) constant returns (bool) {
return ownerIndex[_addr] > 0;
}
function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) {
var pending = pendings[_operation];
uint index = ownerIndex[_owner];
// make sure they're an owner
if (index == 0) {
return false;
}
// determine the bit to set for this owner.
uint ownerIndexBit = 2**index;
return !(pending.ownersDone & ownerIndexBit == 0);
}
// returns true when operation can be executed
function confirmAndCheck(bytes32 _operation) internal returns (bool) {
// determine what index the present sender is:
uint index = ownerIndex[msg.sender];
// make sure they're an owner
if (index == 0) {
throw;
}
var pending = pendings[_operation];
// if we're not yet working on this operation, switch over and reset the confirmation status.
if (pending.yetNeeded == 0) {
// reset count of confirmations needed.
pending.yetNeeded = required;
// reset which owners have confirmed (none) - set our bitmap to 0.
pending.ownersDone = 0;
pending.index = pendingsIndex.length++;
pendingsIndex[pending.index] = _operation;
}
// determine the bit to set for this owner.
uint ownerIndexBit = 2**index;
// make sure we (the message sender) haven't confirmed this operation previously.
if (pending.ownersDone & ownerIndexBit == 0) {
Confirmation(msg.sender, _operation);
// ok - check if count is enough to go ahead.
if (pending.yetNeeded <= 1) {
// enough confirmations: reset and run interior.
delete pendingsIndex[pendings[_operation].index];
delete pendings[_operation];
return true;
} else {
// not enough: record that this owner in particular confirmed.
pending.yetNeeded--;
pending.ownersDone |= ownerIndexBit;
}
}
return false;
}
function clearPending() internal {
uint length = pendingsIndex.length;
for (uint i = 0; i < length; ++i) {
if (pendingsIndex[i] != 0) {
delete pendings[pendingsIndex[i]];
}
}
delete pendingsIndex;
}
}
================================================
FILE: resources/public/contracts/src/SingleFileContribution.sol
================================================
pragma solidity ^0.4.11;
library SafeMath {
function mul(uint a, uint b) internal returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint a, uint b) internal returns (uint) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint a, uint b) internal returns (uint) {
assert(b <= a);
return a - b;
}
function add(uint a, uint b) internal returns (uint) {
uint c = a + b;
assert(c >= a);
return c;
}
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
return a < b ? a : b;
}
function assert(bool assertion) internal {
if (!assertion) {
throw;
}
}
}
contract Ownable {
/// @dev `owner` is the only address that can call a function with this
/// modifier
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
address public owner;
/// @notice The Constructor assigns the message sender to be `owner`
function Ownable() {
owner = msg.sender;
}
address public newOwner;
/// @notice `owner` can step down and assign some other address to this role
/// @param _newOwner The address of the new owner.
function changeOwner(address _newOwner) onlyOwner {
newOwner = _newOwner;
}
function acceptOwnership() {
if (msg.sender == newOwner) {
owner = newOwner;
}
}
}
contract Pausable is Ownable {
bool public stopped;
event onEmergencyChanged(bool isStopped);
modifier stopInEmergency {
if (stopped) {
throw;
}
_;
}
modifier onlyInEmergency {
if (!stopped) {
throw;
}
_;
}
// called by the owner on emergency, triggers stopped state
function emergencyStop() external onlyOwner {
stopped = true;
onEmergencyChanged(stopped);
}
// called by the owner on end of emergency, returns to normal state
function release() external onlyOwner onlyInEmergency {
stopped = false;
onEmergencyChanged(stopped);
}
}
contract ERC20Basic {
function totalSupply() constant returns (uint);
function balanceOf(address who) constant returns (uint);
function transfer(address to, uint value) returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
}
contract ERC20 is ERC20Basic {
mapping(address => uint) balances;
function allowance(address owner, address spender) constant returns (uint);
function transferFrom(address from, address to, uint value) returns (bool);
function approve(address spender, uint value) returns (bool);
function approveAndCall(address spender, uint256 value, bytes extraData) returns (bool);
event Approval(address indexed owner, address indexed spender, uint value);
function doTransfer(address _from, address _to, uint _amount) internal returns(bool);
}
contract GrantsControlled {
modifier onlyGrantsController { if (msg.sender != grantsController) throw; _; }
address public grantsController;
function GrantsControlled() { grantsController = msg.sender;}
function changeGrantsController(address _newController) onlyGrantsController {
grantsController = _newController;
}
}
contract LimitedTransferToken is ERC20 {
// Checks whether it can transfer or otherwise throws.
modifier canTransfer(address _sender, uint _value) {
if (_value > transferableTokens(_sender, uint64(now))) throw;
_;
}
// Checks modifier and allows transfer if tokens are not locked.
function transfer(address _to, uint _value) canTransfer(msg.sender, _value) returns (bool) {
return super.transfer(_to, _value);
}
// Checks modifier and allows transfer if tokens are not locked.
function transferFrom(address _from, address _to, uint _value) canTransfer(_from, _value) returns (bool) {
return super.transferFrom(_from, _to, _value);
}
// Default transferable tokens function returns all tokens for a holder (no limit).
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
return balanceOf(holder);
}
}
contract Controlled {
/// @notice The address of the controller is the only address that can call
/// a function with this modifier
modifier onlyController { if (msg.sender != controller) throw; _; }
address public controller;
function Controlled() { controller = msg.sender;}
/// @notice Changes the controller of the contract
/// @param _newController The new controller of the contract
function changeController(address _newController) onlyController {
controller = _newController;
}
}
contract MiniMeToken is ERC20, Controlled {
using SafeMath for uint;
string public name; //The Token's name: e.g. DigixDAO Tokens
uint8 public decimals; //Number of decimals of the smallest unit
string public symbol; //An identifier: e.g. REP
string public version = 'MMT_0.1'; //An arbitrary versioning scheme
/// @dev `Checkpoint` is the structure that attaches a block number to a
/// given value, the block number attached is the one that last changed the
/// value
struct Checkpoint {
// `fromBlock` is the block number that the value was generated from
uint128 fromBlock;
// `value` is the amount of tokens at a specific block number
uint128 value;
}
// `parentToken` is the Token address that was cloned to produce this token;
// it will be 0x0 for a token that was not cloned
MiniMeToken public parentToken;
// `parentSnapShotBlock` is the block number from the Parent Token that was
// used to determine the initial distribution of the Clone Token
uint public parentSnapShotBlock;
// `creationBlock` is the block number that the Clone Token was created
uint public creationBlock;
// `balances` is the map that tracks the balance of each address, in this
// contract when the balance changes the block number that the change
// occurred is also included in the map
mapping (address => Checkpoint[]) balances;
// `allowed` tracks any extra transfer rights as in all ERC20 tokens
mapping (address => mapping (address => uint256)) allowed;
// Tracks the history of the `totalSupply` of the token
Checkpoint[] totalSupplyHistory;
// Flag that determines if the token is transferable or not.
bool public transfersEnabled;
// The factory used to create new clone tokens
MiniMeTokenFactory public tokenFactory;
////////////////
// Constructor
////////////////
/// @notice Constructor to create a MiniMeToken
/// @param _tokenFactory The address of the MiniMeTokenFactory contract that
/// will create the Clone token contracts, the token factory needs to be
/// deployed first
/// @param _parentToken Address of the parent token, set to 0x0 if it is a
/// new token
/// @param _parentSnapShotBlock Block of the parent token that will
/// determine the initial distribution of the clone token, set to 0 if it
/// is a new token
/// @param _tokenName Name of the new token
/// @param _decimalUnits Number of decimals of the new token
/// @param _tokenSymbol Token Symbol for the new token
/// @param _transfersEnabled If true, tokens will be able to be transferred
function MiniMeToken(
address _tokenFactory,
address _parentToken,
uint _parentSnapShotBlock,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
bool _transfersEnabled
) {
tokenFactory = MiniMeTokenFactory(_tokenFactory);
name = _tokenName; // Set the name
decimals = _decimalUnits; // Set the decimals
symbol = _tokenSymbol; // Set the symbol
parentToken = MiniMeToken(_parentToken);
parentSnapShotBlock = _parentSnapShotBlock;
transfersEnabled = _transfersEnabled;
creationBlock = block.number;
}
///////////////////
// ERC20 Methods
///////////////////
/// @notice Send `_amount` tokens to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint256 _amount) returns (bool success) {
if (!transfersEnabled) throw;
return doTransfer(msg.sender, _to, _amount);
}
/// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
/// is approved by `_from`
/// @param _from The address holding the tokens being transferred
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return True if the transfer was successful
function transferFrom(address _from, address _to, uint256 _amount
) returns (bool success) {
// The controller of this contract can move tokens around at will,
// this is important to recognize! Confirm that you trust the
// controller of this contract, which in most situations should be
// another open source smart contract or 0x0
if (msg.sender != controller) {
if (!transfersEnabled) throw;
// The standard ERC 20 transferFrom functionality
if (allowed[_from][msg.sender] < _amount) return false;
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_amount);
}
return doTransfer(_from, _to, _amount);
}
/// @dev This is the actual transfer function in the token contract, it can
/// only be called by other functions in this contract.
/// @param _from The address holding the tokens being transferred
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return True if the transfer was successful
function doTransfer(address _from, address _to, uint _amount
) internal returns(bool) {
if (_amount == 0) {
return true;
}
if (parentSnapShotBlock >= block.number) throw;
// Do not allow transfer to 0x0 or the token contract itself
if ((_to == 0) || (_to == address(this))) throw;
// If the amount being transfered is more than the balance of the
// account the transfer returns false
var previousBalanceFrom = balanceOfAt(_from, block.number);
if (previousBalanceFrom < _amount) {
return false;
}
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
throw;
}
// First update the balance array with the new value for the address
// sending the tokens
updateValueAtNow(balances[_from], previousBalanceFrom.sub(_amount));
// Then update the balance array with the new value for the address
// receiving the tokens
var previousBalanceTo = balanceOfAt(_to, block.number);
updateValueAtNow(balances[_to], previousBalanceTo.add(_amount));
// An event to make the transfer easy to find on the blockchain
Transfer(_from, _to, _amount);
return true;
}
/// @param _owner The address that's balance is being requested
/// @return The balance of `_owner` at the current block
function balanceOf(address _owner) constant returns (uint256 balance) {
return balanceOfAt(_owner, block.number);
}
/// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
/// its behalf. This is a modified version of the ERC20 approve function
/// to be a little bit safer
/// @param _spender The address of the account able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the approval was successful
function approve(address _spender, uint256 _amount) returns (bool success) {
if (!transfersEnabled) throw;
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender,0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
if ((_amount!=0) && (allowed[msg.sender][_spender] !=0)) throw;
// Alerts the token controller of the approve function call
if (isContract(controller)) {
if (!TokenController(controller).onApprove(msg.sender, _spender, _amount))
throw;
}
allowed[msg.sender][_spender] = _amount;
Approval(msg.sender, _spender, _amount);
return true;
}
/// @dev This function makes it easy to read the `allowed[]` map
/// @param _owner The address of the account that owns the token
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens of _owner that _spender is allowed
/// to spend
function allowance(address _owner, address _spender
) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
/// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
/// its behalf, and then a function is triggered in the contract that is
/// being approved, `_spender`. This allows users to use their tokens to
/// interact with contracts in one function call instead of two
/// @param _spender The address of the contract able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the function call was successful
function approveAndCall(address _spender, uint256 _amount, bytes _extraData
) returns (bool success) {
if (!approve(_spender, _amount)) throw;
ApproveAndCallFallBack(_spender).receiveApproval(
msg.sender,
_amount,
this,
_extraData
);
return true;
}
/// @dev This function makes it easy to get the total number of tokens
/// @return The total number of tokens
function totalSupply() constant returns (uint) {
return totalSupplyAt(block.number);
}
////////////////
// Query balance and totalSupply in History
////////////////
/// @dev Queries the balance of `_owner` at a specific `_blockNumber`
/// @param _owner The address from which the balance will be retrieved
/// @param _blockNumber The block number when the balance is queried
/// @return The balance at `_blockNumber`
function balanceOfAt(address _owner, uint _blockNumber) constant
returns (uint) {
// These next few lines are used when the balance of the token is
// requested before a check point was ever created for this token, it
// requires that the `parentToken.balanceOfAt` be queried at the
// genesis block for that token as this contains initial balance of
// this token
if ((balances[_owner].length == 0)
|| (balances[_owner][0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
} else {
// Has no parent
return 0;
}
// This will return the expected balance during normal situations
} else {
return getValueAt(balances[_owner], _blockNumber);
}
}
/// @notice Total amount of tokens at a specific `_blockNumber`.
/// @param _blockNumber The block number when the totalSupply is queried
/// @return The total amount of tokens at `_blockNumber`
function totalSupplyAt(uint _blockNumber) constant returns(uint) {
// These next few lines are used when the totalSupply of the token is
// requested before a check point was ever created for this token, it
// requires that the `parentToken.totalSupplyAt` be queried at the
// genesis block for this token as that contains totalSupply of this
// token at this block number.
if ((totalSupplyHistory.length == 0)
|| (totalSupplyHistory[0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
} else {
return 0;
}
// This will return the expected totalSupply during normal situations
} else {
return getValueAt(totalSupplyHistory, _blockNumber);
}
}
////////////////
// Clone Token Method
////////////////
/// @notice Creates a new clone token with the initial distribution being
/// this token at `_snapshotBlock`
/// @param _cloneTokenName Name of the clone token
/// @param _cloneDecimalUnits Number of decimals of the smallest unit
/// @param _cloneTokenSymbol Symbol of the clone token
/// @param _snapshotBlock Block when the distribution of the parent token is
/// copied to set the initial distribution of the new clone token;
/// if the block is zero than the actual block, the current block is used
/// @param _transfersEnabled True if transfers are allowed in the clone
/// @return The address of the new MiniMeToken Contract
function createCloneToken(
string _cloneTokenName,
uint8 _cloneDecimalUnits,
string _cloneTokenSymbol,
uint _snapshotBlock,
bool _transfersEnabled
) returns(address) {
if (_snapshotBlock == 0) _snapshotBlock = block.number;
MiniMeToken cloneToken = tokenFactory.createCloneToken(
this,
_snapshotBlock,
_cloneTokenName,
_cloneDecimalUnits,
_cloneTokenSymbol,
_transfersEnabled
);
cloneToken.changeController(msg.sender);
// An event to make the token easy to find on the blockchain
NewCloneToken(address(cloneToken), _snapshotBlock);
return address(cloneToken);
}
////////////////
// Generate and destroy tokens
////////////////
/// @notice Generates `_amount` tokens that are assigned to `_owner`
/// @param _owner The address that will be assigned the new tokens
/// @param _amount The quantity of tokens generated
/// @return True if the tokens are generated correctly
function generateTokens(address _owner, uint _amount
) onlyController returns (bool) {
uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
updateValueAtNow(totalSupplyHistory, curTotalSupply.add(_amount));
var previousBalanceTo = balanceOf(_owner);
updateValueAtNow(balances[_owner], previousBalanceTo.add(_amount));
Transfer(0, _owner, _amount);
return true;
}
/// @notice Burns `_amount` tokens from `_owner`
/// @param _owner The address that will lose the tokens
/// @param _amount The quantity of tokens to burn
/// @return True if the tokens are burned correctly
function destroyTokens(address _owner, uint _amount
) onlyController returns (bool) {
uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
if (curTotalSupply < _amount) throw;
updateValueAtNow(totalSupplyHistory, curTotalSupply.sub(_amount));
var previousBalanceFrom = balanceOf(_owner);
if (previousBalanceFrom < _amount) throw;
updateValueAtNow(balances[_owner], previousBalanceFrom.sub(_amount));
Transfer(_owner, 0, _amount);
return true;
}
////////////////
// Enable tokens transfers
////////////////
/// @notice Enables token holders to transfer their tokens freely if true
/// @param _transfersEnabled True if transfers are allowed in the clone
function enableTransfers(bool _transfersEnabled) onlyController {
transfersEnabled = _transfersEnabled;
}
////////////////
// Internal helper functions to query and set a value in a snapshot array
////////////////
/// @dev `getValueAt` retrieves the number of tokens at a given block number
/// @param checkpoints The history of values being queried
/// @param _block The block number to retrieve the value at
/// @return The number of tokens being queried
function getValueAt(Checkpoint[] storage checkpoints, uint _block
) constant internal returns (uint) {
if (checkpoints.length == 0) return 0;
// Shortcut for the actual value
if (_block >= checkpoints[checkpoints.length-1].fromBlock)
return checkpoints[checkpoints.length-1].value;
if (_block < checkpoints[0].fromBlock) return 0;
// Binary search of the value in the array
uint min = 0;
uint max = checkpoints.length-1;
while (max > min) {
uint mid = (max + min + 1)/ 2;
if (checkpoints[mid].fromBlock<=_block) {
min = mid;
} else {
max = mid-1;
}
}
return checkpoints[min].value;
}
/// @dev `updateValueAtNow` used to update the `balances` map and the
/// `totalSupplyHistory`
/// @param checkpoints The history of data being updated
/// @param _value The new number of tokens
function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value
) internal {
if ((checkpoints.length == 0)
|| (checkpoints[checkpoints.length -1].fromBlock < block.number)) {
Checkpoint newCheckPoint = checkpoints[ checkpoints.length++ ];
newCheckPoint.fromBlock = uint128(block.number);
newCheckPoint.value = uint128(_value);
} else {
Checkpoint oldCheckPoint = checkpoints[checkpoints.length-1];
oldCheckPoint.value = uint128(_value);
}
}
/// @dev Internal function to determine if an address is a contract
/// @param _addr The address being queried
/// @return True if `_addr` is a contract
function isContract(address _addr) constant internal returns(bool) {
uint size;
if (_addr == 0) return false;
assembly {
size := extcodesize(_addr)
}
return size>0;
}
/// @dev Helper function to return a min betwen the two uints
function min(uint a, uint b) internal returns (uint) {
return a < b ? a : b;
}
/// @notice The fallback function: If the contract's controller has not been
/// set to 0, then the `proxyPayment` method is called which relays the
/// ether and creates tokens as described in the token controller contract
function () payable {
if (isContract(controller)) {
if (! TokenController(controller).proxyPayment.value(msg.value)(msg.sender))
throw;
} else {
throw;
}
}
//////////
// Safety Methods
//////////
/// @notice This method can be used by the controller to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0 in case you want to extract ether.
/// @param _claimer Address that tokens will be send to
function claimTokens(address _token, address _claimer) onlyController {
if (_token == 0x0) {
_claimer.transfer(this.balance);
return;
}
ERC20Basic token = ERC20Basic(_token);
uint balance = token.balanceOf(this);
token.transfer(_claimer, balance);
ClaimedTokens(_token, _claimer, balance);
}
////////////////
// Events
////////////////
event ClaimedTokens(address indexed _token, address indexed _claimer, uint _amount);
event Transfer(address indexed _from, address indexed _to, uint256 _amount);
event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _amount
);
}
////////////////
// MiniMeTokenFactory
////////////////
/// @dev This contract is used to generate clone contracts from a contract.
/// In solidity this is the way to create a contract from a contract of the
/// same class
contract MiniMeTokenFactory {
/// @notice Update the DApp by creating a new token with new functionalities
/// the msg.sender becomes the controller of this clone token
/// @param _parentToken Address of the token being cloned
/// @param _snapshotBlock Block of the parent token that will
/// determine the initial distribution of the clone token
/// @param _tokenName Name of the new token
/// @param _decimalUnits Number of decimals of the new token
/// @param _tokenSymbol Token Symbol for the new token
/// @param _transfersEnabled If true, tokens will be able to be transferred
/// @return The address of the new token contract
function createCloneToken(
address _parentToken,
uint _snapshotBlock,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
bool _transfersEnabled
) returns (MiniMeToken) {
MiniMeToken newToken = new MiniMeToken(
this,
_parentToken,
_snapshotBlock,
_tokenName,
_decimalUnits,
_tokenSymbol,
_transfersEnabled
);
newToken.changeController(msg.sender);
return newToken;
}
}
contract VestedToken is LimitedTransferToken, GrantsControlled {
using SafeMath for uint;
uint256 MAX_GRANTS_PER_ADDRESS = 20;
struct TokenGrant {
address granter; // 20 bytes
uint256 value; // 32 bytes
uint64 cliff;
uint64 vesting;
uint64 start; // 3 * 8 = 24 bytes
bool revokable;
bool burnsOnRevoke; // 2 * 1 = 2 bits? or 2 bytes?
} // total 78 bytes = 3 sstore per operation (32 per sstore)
mapping (address => TokenGrant[]) public grants;
event NewTokenGrant(address indexed from, address indexed to, uint256 value, uint256 grantId);
/**
* @dev Grant tokens to a specified address
* @param _to address The address which the tokens will be granted to.
* @param _value uint256 The amount of tokens to be granted.
* @param _start uint64 Time of the beginning of the grant.
* @param _cliff uint64 Time of the cliff period.
* @param _vesting uint64 The vesting period.
*/
function grantVestedTokens(
address _to,
uint256 _value,
uint64 _start,
uint64 _cliff,
uint64 _vesting,
bool _revokable,
bool _burnsOnRevoke
) onlyGrantsController public {
// Check for date inconsistencies that may cause unexpected behavior
if (_cliff < _start || _vesting < _cliff) {
throw;
}
if (tokenGrantsCount(_to) > MAX_GRANTS_PER_ADDRESS) throw; // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).
uint count = grants[_to].push(
TokenGrant(
_revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
_value,
_cliff,
_vesting,
_start,
_revokable,
_burnsOnRevoke
)
);
transfer(_to, _value);
NewTokenGrant(msg.sender, _to, _value, count - 1);
}
/**
* @dev Revoke the grant of tokens of a specifed address.
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
*/
function revokeTokenGrant(address _holder, uint _grantId) public {
TokenGrant grant = grants[_holder][_grantId];
if (!grant.revokable) { // Check if grant was revokable
throw;
}
if (grant.granter != msg.sender) { // Only granter can revoke it
throw;
}
address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;
uint256 nonVested = nonVestedTokens(grant, uint64(now));
// remove grant from array
delete grants[_holder][_grantId];
grants[_holder][_grantId] = grants[_holder][grants[_holder].length.sub(1)];
grants[_holder].length -= 1;
// This will call MiniMe's doTransfer method, so token is transferred according to
// MiniMe Token logic
doTransfer(_holder, receiver, nonVested);
Transfer(_holder, receiver, nonVested);
}
/**
* @dev Revoke all grants of tokens of a specifed address.
* @param _holder The address which will have its tokens revoked.
*/
function revokeAllTokenGrants(address _holder) {
var grandsCount = tokenGrantsCount(_holder);
for (uint i = 0; i < grandsCount; i++) {
revokeTokenGrant(_holder, 0);
}
}
/**
* @dev Calculate the total amount of transferable tokens of a holder at a given time
* @param holder address The address of the holder
* @param time uint64 The specific time.
* @return An uint representing a holder's total amount of transferable tokens.
*/
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
uint256 grantIndex = tokenGrantsCount(holder);
if (grantIndex == 0) return balanceOf(holder); // shortcut for holder without grants
// Iterate through all the grants the holder has, and add all non-vested tokens
uint256 nonVested = 0;
for (uint256 i = 0; i < grantIndex; i++) {
nonVested = SafeMath.add(nonVested, nonVestedTokens(grants[holder][i], time));
}
// Balance - totalNonVested is the amount of tokens a holder can transfer at any given time
uint256 vestedTransferable = SafeMath.sub(balanceOf(holder), nonVested);
// Return the minimum of how many vested can transfer and other value
// in case there are other limiting transferability factors (default is balanceOf)
return SafeMath.min256(vestedTransferable, super.transferableTokens(holder, time));
}
/**
* @dev Check the amount of grants that an address has.
* @param _holder The holder of the grants.
* @return A uint representing the total amount of grants.
*/
function tokenGrantsCount(address _holder) constant returns (uint index) {
return grants[_holder].length;
}
/**
* @dev Calculate amount of vested tokens at a specifc time.
* @param tokens uint256 The amount of tokens grantted.
* @param time uint64 The time to be checked
* @param start uint64 A time representing the begining of the grant
* @param cliff uint64 The cliff period.
* @param vesting uint64 The vesting period.
* @return An uint representing the amount of vested tokensof a specif grant.
* transferableTokens
* | _/-------- vestedTokens rect
* | _/
* | _/
* | _/
* | _/
* | /
* | .|
* | . |
* | . |
* | . |
* | . |
* | . |
* +===+===========+---------+----------> time
* Start Clift Vesting
*/
function calculateVestedTokens(
uint256 tokens,
uint256 time,
uint256 start,
uint256 cliff,
uint256 vesting) constant returns (uint256)
{
// Shortcuts for before cliff and after vesting cases.
if (time < cliff) return 0;
if (time >= vesting) return tokens;
// Interpolate all vested tokens.
// As before cliff the shortcut returns 0, we can use just calculate a value
// in the vesting rect (as shown in above's figure)
// vestedTokens = tokens * (time - start) / (vesting - start)
uint256 vestedTokens = SafeMath.div(
SafeMath.mul(
tokens,
SafeMath.sub(time, start)
),
SafeMath.sub(vesting, start)
);
return vestedTokens;
}
/**
* @dev Get all information about a specifc grant.
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
* @return Returns all the values that represent a TokenGrant(address, value, start, cliff,
* revokability, burnsOnRevoke, and vesting) plus the vested value at the current time.
*/
function tokenGrant(address _holder, uint _grantId) constant returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
TokenGrant grant = grants[_holder][_grantId];
granter = grant.granter;
value = grant.value;
start = grant.start;
cliff = grant.cliff;
vesting = grant.vesting;
revokable = grant.revokable;
burnsOnRevoke = grant.burnsOnRevoke;
vested = vestedTokens(grant, uint64(now));
}
/**
* @dev Get the amount of vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time The time to be checked
* @return An uint representing the amount of vested tokens of a specific grant at a specific time.
*/
function vestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return calculateVestedTokens(
grant.value,
uint256(time),
uint256(grant.start),
uint256(grant.cliff),
uint256(grant.vesting)
);
}
/**
* @dev Calculate the amount of non vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time uint64 The time to be checked
* @return An uint representing the amount of non vested tokens of a specifc grant on the
* passed time frame.
*/
function nonVestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return grant.value.sub(vestedTokens(grant, time));
}
/**
* @dev Calculate the date when the holder can trasfer all its tokens
* @param holder address The address of the holder
* @return An uint representing the date of the last transferable tokens.
*/
function lastTokenIsTransferableDate(address holder) constant public returns (uint64 date) {
date = uint64(now);
uint256 grantIndex = grants[holder].length;
for (uint256 i = 0; i < grantIndex; i++) {
date = SafeMath.max64(grants[holder][i].vesting, date);
}
}
}
contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 _amount, address _token, bytes _data);
}
contract TokenController {
/// @notice Called when `_owner` sends ether to the MiniMe Token contract
/// @param _owner The address that sent the ether to create tokens
/// @return True if the ether is accepted, false if it throws
function proxyPayment(address _owner) payable returns(bool);
/// @notice Notifies the controller about a token transfer allowing the
/// controller to react if desired
/// @param _from The origin of the transfer
/// @param _to The destination of the transfer
/// @param _amount The amount of the transfer
/// @return False if the controller does not authorize the transfer
function onTransfer(address _from, address _to, uint _amount) returns(bool);
/// @notice Notifies the controller about an approval allowing the
/// controller to react if desired
/// @param _owner The address that calls `approve()`
/// @param _spender The spender in the `approve()` call
/// @param _amount The amount in the `approve()` call
/// @return False if the controller does not authorize the approval
function onApprove(address _owner, address _spender, uint _amount)
returns(bool);
}
contract District0xNetworkToken is MiniMeToken, VestedToken {
function District0xNetworkToken(address _controller, address _tokenFactory)
MiniMeToken(
_tokenFactory,
0x0, // no parent token
0, // no snapshot block number from parent
"district0x Network Token", // Token name
18, // Decimals
"DNT", // Symbol
true // Enable transfers
)
{
changeController(_controller);
changeGrantsController(_controller);
}
}
contract HasNoTokens is Ownable {
District0xNetworkToken public district0xNetworkToken;
/**
* @dev Reject all ERC23 compatible tokens
* @param from_ address The address that is transferring the tokens
* @param value_ uint256 the amount of the specified token
* @param data_ Bytes The data passed from the caller.
*/
function tokenFallback(address from_, uint256 value_, bytes data_) external {
throw;
}
function isTokenSaleToken(address tokenAddr) returns(bool);
/**
* @dev Reclaim all ERC20Basic compatible tokens
* @param tokenAddr address The address of the token contract
*/
function reclaimToken(address tokenAddr) external onlyOwner {
require(!isTokenSaleToken(tokenAddr));
ERC20Basic tokenInst = ERC20Basic(tokenAddr);
uint256 balance = tokenInst.balanceOf(this);
tokenInst.transfer(msg.sender, balance);
}
}
contract District0xContribution is Pausable, HasNoTokens, TokenController {
using SafeMath for uint;
District0xNetworkToken public district0xNetworkToken;
address public multisigWallet; // Wallet that receives all sale funds
address public founder1; // Wallet of founder 1
address public founder2; // Wallet of founder 2
address public earlySponsor; // Wallet of early sponsor
address[] public advisers; // 4 Wallets of advisors
uint public constant FOUNDER1_STAKE = 119000000 ether; // 119M DNT
uint public constant FOUNDER2_STAKE = 79000000 ether; // 79M DNT
uint public constant EARLY_CONTRIBUTOR_STAKE = 5000000 ether; // 5M DNT
uint public constant ADVISER_STAKE = 5000000 ether; // 5M DNT
uint public constant ADVISER_STAKE2 = 1000000 ether; // 1M DNT
uint public constant COMMUNITY_ADVISERS_STAKE = 5000000 ether; // 5M DNT
uint public constant CONTRIB_PERIOD1_STAKE = 600000000 ether; // 600M DNT
uint public constant CONTRIB_PERIOD2_STAKE = 140000000 ether; // 140M DNT
uint public constant CONTRIB_PERIOD3_STAKE = 40000000 ether; // 40M DNT
uint public minContribAmount = 0.01 ether; // 0.01 ether
uint public maxGasPrice = 50000000000; // 50 GWei
uint public constant TEAM_VESTING_CLIFF = 24 weeks; // 6 months vesting cliff for founders and advisors, except community advisors
uint public constant TEAM_VESTING_PERIOD = 96 weeks; // 2 years vesting period for founders and advisors, except community advisors
uint public constant EARLY_CONTRIBUTOR_VESTING_CLIFF = 12 weeks; // 3 months vesting cliff for early sponsor
uint public constant EARLY_CONTRIBUTOR_VESTING_PERIOD = 24 weeks; // 6 months vesting cliff for early sponsor
bool public tokenTransfersEnabled = false; // DNT token transfers will be enabled manually
// after first contribution period
// Can't be disabled back
struct Contributor {
uint amount; // Amount of ETH contributed by an address in given contribution period
bool isCompensated; // Whether this contributor received DNT token for ETH contribution
uint amountCompensated; // Amount of DNT received. Not really needed to store,
// but stored for accounting and security purposes
}
uint public softCapAmount; // Soft cap of contribution period in wei
uint public afterSoftCapDuration; // Number of seconds to the end of sale from the moment of reaching soft cap (unless reaching hardcap)
uint public hardCapAmount; // When reached this amount of wei, the contribution will end instantly
uint public startTime; // Start time of contribution period in UNIX time
uint public endTime; // End time of contribution period in UNIX time
bool public isEnabled; // If contribution period was enabled by multisignature
bool public softCapReached; // If soft cap was reached
bool public hardCapReached; // If hard cap was reached
uint public totalContributed; // Total amount of ETH contributed in given period
address[] public contributorsKeys; // Addresses of all contributors in given contribution period
mapping (address => Contributor) public contributors;
event onContribution(uint totalContributed, address indexed contributor, uint amount,
uint contributorsCount);
event onSoftCapReached(uint endTime);
event onHardCapReached(uint endTime);
event onCompensated(address indexed contributor, uint amount);
modifier onlyMultisig() {
require(multisigWallet == msg.sender);
_;
}
function District0xContribution(
address _multisigWallet,
address _founder1,
address _founder2,
address _earlySponsor,
address[] _advisers
) {
require(_advisers.length == 5);
multisigWallet = _multisigWallet;
founder1 = _founder1;
founder2 = _founder2;
earlySponsor = _earlySponsor;
advisers = _advisers;
}
// @notice Returns true if contribution period is currently running
function isContribPeriodRunning() constant returns (bool) {
return !hardCapReached &&
isEnabled &&
startTime <= now &&
endTime > now;
}
function contribute()
payable
stopInEmergency
{
contributeWithAddress(msg.sender);
}
// @notice Function to participate in contribution period
// Amounts from the same address should be added up
// If soft or hard cap is reached, end time should be modified
// Funds should be transferred into multisig wallet
// @param contributor Address that will receive DNT token
function contributeWithAddress(address contributor)
payable
stopInEmergency
{
require(tx.gasprice <= maxGasPrice);
require(msg.value >= minContribAmount);
require(isContribPeriodRunning());
uint contribValue = msg.value;
uint excessContribValue = 0;
uint oldTotalContributed = totalContributed;
totalContributed = oldTotalContributed.add(contribValue);
uint newTotalContributed = totalContributed;
// Soft cap was reached
if (newTotalContributed >= softCapAmount &&
oldTotalContributed < softCapAmount)
{
softCapReached = true;
endTime = afterSoftCapDuration.add(now);
onSoftCapReached(endTime);
}
// Hard cap was reached
if (newTotalContributed >= hardCapAmount &&
oldTotalContributed < hardCapAmount)
{
hardCapReached = true;
endTime = now;
onHardCapReached(endTime);
// Everything above hard cap will be sent back to contributor
excessContribValue = newTotalContributed.sub(hardCapAmount);
contribValue = contribValue.sub(excessContribValue);
totalContributed = hardCapAmount;
}
if (contributors[contributor].amount == 0) {
contributorsKeys.push(contributor);
}
contributors[contributor].amount = contributors[contributor].amount.add(contribValue);
multisigWallet.transfer(contribValue);
if (excessContribValue > 0) {
msg.sender.transfer(excessContribValue);
}
onContribution(newTotalContributed, contributor, contribValue, contributorsKeys.length);
}
// @notice This method is called by owner after contribution period ends, to distribute DNT in proportional manner
// Each contributor should receive DNT just once even if this method is called multiple times
// In case of many contributors must be able to compensate contributors in paginational way, otherwise might
// run out of gas if wanted to compensate all on one method call. Therefore parameters offset and limit
// @param periodIndex Index of contribution period (0-2)
// @param offset Number of first contributors to skip.
// @param limit Max number of contributors compensated on this call
function compensateContributors(uint offset, uint limit)
onlyOwner
{
require(isEnabled);
require(endTime < now);
uint i = offset;
uint compensatedCount = 0;
uint contributorsCount = contributorsKeys.length;
uint ratio = CONTRIB_PERIOD1_STAKE
.mul(1000000000000000000)
.div(totalContributed);
while (i < contributorsCount && compensatedCount < limit) {
address contributorAddress = contributorsKeys[i];
if (!contributors[contributorAddress].isCompensated) {
uint amountContributed = contributors[contributorAddress].amount;
contributors[contributorAddress].isCompensated = true;
contributors[contributorAddress].amountCompensated =
amountContributed.mul(ratio).div(1000000000000000000);
district0xNetworkToken.transfer(contributorAddress, contributors[contributorAddress].amountCompensated);
onCompensated(contributorAddress, contributors[contributorAddress].amountCompensated);
compensatedCount++;
}
i++;
}
}
// @notice Method for setting up contribution period
// Only owner should be able to execute
// Setting first contribution period sets up vesting for founders & advisors
// Contribution period should still not be enabled after calling this method
// @param softCapAmount Soft Cap in wei
// @param afterSoftCapDuration Number of seconds till the end of sale in the moment of reaching soft cap (unless reaching hard cap)
// @param hardCapAmount Hard Cap in wei
// @param startTime Contribution start time in UNIX time
// @param endTime Contribution end time in UNIX time
function setContribPeriod(
uint _softCapAmount,
uint _afterSoftCapDuration,
uint _hardCapAmount,
uint _startTime,
uint _endTime
)
onlyOwner
{
require(_softCapAmount > 0);
require(_hardCapAmount > _softCapAmount);
require(_afterSoftCapDuration > 0);
require(_startTime > now);
require(_endTime > _startTime);
require(!isEnabled);
softCapAmount = _softCapAmount;
afterSoftCapDuration = _afterSoftCapDuration;
hardCapAmount = _hardCapAmount;
startTime = _startTime;
endTime = _endTime;
district0xNetworkToken.revokeAllTokenGrants(founder1);
district0xNetworkToken.revokeAllTokenGrants(founder2);
district0xNetworkToken.revokeAllTokenGrants(earlySponsor);
for (uint j = 0; j < advisers.length; j++) {
district0xNetworkToken.revokeAllTokenGrants(advisers[j]);
}
uint64 vestingDate = uint64(startTime.add(TEAM_VESTING_PERIOD));
uint64 cliffDate = uint64(startTime.add(TEAM_VESTING_CLIFF));
uint64 earlyContribVestingDate = uint64(startTime.add(EARLY_CONTRIBUTOR_VESTING_PERIOD));
uint64 earlyContribCliffDate = uint64(startTime.add(EARLY_CONTRIBUTOR_VESTING_CLIFF));
uint64 startDate = uint64(startTime);
district0xNetworkToken.grantVestedTokens(founder1, FOUNDER1_STAKE, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(founder2, FOUNDER2_STAKE, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(earlySponsor, EARLY_CONTRIBUTOR_STAKE, startDate, earlyContribCliffDate, earlyContribVestingDate, true, false);
district0xNetworkToken.grantVestedTokens(advisers[0], ADVISER_STAKE, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(advisers[1], ADVISER_STAKE, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(advisers[2], ADVISER_STAKE2, startDate, cliffDate, vestingDate, true, false);
district0xNetworkToken.grantVestedTokens(advisers[3], ADVISER_STAKE2, startDate, cliffDate, vestingDate, true, false);
// Community advisors stake has no vesting, but we set it up this way, so we can revoke it in case of
// re-setting up contribution period
district0xNetworkToken.grantVestedTokens(advisers[4], COMMUNITY_ADVISERS_STAKE, startDate, startDate, startDate, true, false);
}
// @notice Enables contribution period
// Must be executed by multisignature
function enableContribPeriod()
onlyMultisig
{
require(startTime > now);
isEnabled = true;
}
// @notice Sets new min. contribution amount
// Only owner can execute
// Cannot be executed while contribution period is running
// @param _minContribAmount new min. amount
function setMinContribAmount(uint _minContribAmount)
onlyOwner
{
require(_minContribAmount > 0);
require(startTime > now);
minContribAmount = _minContribAmount;
}
// @notice Sets new max gas price for contribution
// Only owner can execute
// Cannot be executed while contribution period is running
// @param _minContribAmount new min. amount
function setMaxGasPrice(uint _maxGasPrice)
onlyOwner
{
require(_maxGasPrice > 0);
require(startTime > now);
maxGasPrice = _maxGasPrice;
}
// @notice Sets District0xNetworkToken contract
// Generates all DNT tokens and assigns them to this contract
// If token contract has already generated tokens, do not generate again
// @param _district0xNetworkToken District0xNetworkToken address
function setDistrict0xNetworkToken(address _district0xNetworkToken)
onlyOwner
{
require(_district0xNetworkToken != 0x0);
require(!isEnabled);
district0xNetworkToken = District0xNetworkToken(_district0xNetworkToken);
if (district0xNetworkToken.totalSupply() == 0) {
district0xNetworkToken.generateTokens(this, FOUNDER1_STAKE
.add(FOUNDER2_STAKE)
.add(EARLY_CONTRIBUTOR_STAKE)
.add(ADVISER_STAKE.mul(2))
.add(ADVISER_STAKE2.mul(2))
.add(COMMUNITY_ADVISERS_STAKE)
.add(CONTRIB_PERIOD1_STAKE));
district0xNetworkToken.generateTokens(multisigWallet, CONTRIB_PERIOD2_STAKE
.add(CONTRIB_PERIOD3_STAKE));
}
}
// @notice Enables transfers of DNT
// Will be executed after first contribution period by owner
function enableDistrict0xNetworkTokenTransfers()
onlyOwner
{
require(endTime < now);
tokenTransfersEnabled = true;
}
// @notice Method to claim tokens accidentally sent to a DNT contract
// Only multisig wallet can execute
// @param _token Address of claimed ERC20 Token
function claimTokensFromTokenDistrict0xNetworkToken(address _token)
onlyMultisig
{
district0xNetworkToken.claimTokens(_token, multisigWallet);
}
// @notice Kill method should not really be needed, but just in case
function kill(address _to) onlyMultisig external {
suicide(_to);
}
function()
payable
stopInEmergency
{
contributeWithAddress(msg.sender);
}
// MiniMe Controller default settings for allowing token transfers.
function proxyPayment(address _owner) payable public returns (bool) {
throw;
}
// Before transfers are enabled for everyone, only this contract is allowed to distribute DNT
function onTransfer(address _from, address _to, uint _amount) public returns (bool) {
return tokenTransfersEnabled || _from == address(this) || _to == address(this);
}
function onApprove(address _owner, address _spender, uint _amount) public returns (bool) {
return tokenTransfersEnabled;
}
function isTokenSaleToken(address tokenAddr) returns(bool) {
return district0xNetworkToken == tokenAddr;
}
/*
Following constant methods are used for tests and contribution web app
They don't impact logic of contribution contract, therefor DOES NOT NEED TO BE AUDITED
*/
// Used by contribution front-end to obtain contribution period properties
function getContribPeriod()
constant
returns (bool[3] boolValues, uint[8] uintValues)
{
boolValues[0] = isEnabled;
boolValues[1] = softCapReached;
boolValues[2] = hardCapReached;
uintValues[0] = softCapAmount;
uintValues[1] = afterSoftCapDuration;
uintValues[2] = hardCapAmount;
uintValues[3] = startTime;
uintValues[4] = endTime;
uintValues[5] = totalContributed;
uintValues[6] = contributorsKeys.length;
uintValues[7] = CONTRIB_PERIOD1_STAKE;
return (boolValues, uintValues);
}
// Used by contribution front-end to obtain contribution contract properties
function getConfiguration()
constant
returns (bool, address, address, address, address, address[] _advisers, bool, uint)
{
_advisers = new address[](advisers.length);
for (uint i = 0; i < advisers.length; i++) {
_advisers[i] = advisers[i];
}
return (stopped, multisigWallet, founder1, founder2, earlySponsor, _advisers, tokenTransfersEnabled,
maxGasPrice);
}
// Used by contribution front-end to obtain contributor's properties
function getContributor(address contributorAddress)
constant
returns(uint, bool, uint)
{
Contributor contributor = contributors[contributorAddress];
return (contributor.amount, contributor.isCompensated, contributor.amountCompensated);
}
// Function to verify if all contributors were compensated
function getUncompensatedContributors(uint offset, uint limit)
constant
returns (uint[] contributorIndexes)
{
uint contributorsCount = contributorsKeys.length;
if (limit == 0) {
limit = contributorsCount;
}
uint i = offset;
uint resultsCount = 0;
uint[] memory _contributorIndexes = new uint[](limit);
while (i < contributorsCount && resultsCount < limit) {
if (!contributors[contributorsKeys[i]].isCompensated) {
_contributorIndexes[resultsCount] = i;
resultsCount++;
}
i++;
}
contributorIndexes = new uint[](resultsCount);
for (i = 0; i < resultsCount; i++) {
contributorIndexes[i] = _contributorIndexes[i];
}
return contributorIndexes;
}
function getNow()
constant
returns(uint)
{
return now;
}
}
================================================
FILE: resources/public/contracts/src/TokenVesting.sol
================================================
pragma solidity ^0.4.18;
import './ERC20Basic.sol';
import './SafeERC20.sol';
import './ownership/Ownable.sol';
import './math/SafeMath.sol';
/**
* @title TokenVesting
* @dev A token holder contract that can release its token balance gradually like a
* typical vesting scheme, with a cliff and vesting period. Optionally revocable by the
* owner.
*/
contract TokenVesting is Ownable {
using SafeMath for uint256;
using SafeERC20 for ERC20Basic;
event Released(uint256 amount);
event Revoked();
// beneficiary of tokens after they are released
address public beneficiary;
uint256 public cliff;
uint256 public start;
uint256 public duration;
bool public revocable;
mapping (address => uint256) public released;
mapping (address => bool) public revoked;
/**
* @dev Creates a vesting contract that vests its balance of any ERC20 token to the
* _beneficiary, gradually in a linear fashion until _start + _duration. By then all
* of the balance will have vested.
* @param _beneficiary address of the beneficiary to whom vested tokens are transferred
* @param _cliff duration in seconds of the cliff in which tokens will begin to vest
* @param _duration duration in seconds of the period in which the tokens will vest
* @param _revocable whether the vesting is revocable or not
*/
function TokenVesting(address _beneficiary, uint256 _start, uint256 _cliff, uint256 _duration, bool _revocable) public {
require(_beneficiary != address(0));
require(_cliff <= _duration);
beneficiary = _beneficiary;
revocable = _revocable;
duration = _duration;
cliff = _start.add(_cliff);
start = _start;
}
/**
* @notice Transfers vested tokens to beneficiary.
* @param token ERC20 token which is being vested
*/
function release(ERC20Basic token) public {
uint256 unreleased = releasableAmount(token);
require(unreleased > 0);
released[token] = released[token].add(unreleased);
token.safeTransfer(beneficiary, unreleased);
Released(unreleased);
}
/**
* @notice Allows the owner to revoke the vesting. Tokens already vested
* remain in the contract, the rest are returned to the owner.
* @param token ERC20 token which is being vested
*/
function revoke(ERC20Basic token) public onlyOwner {
require(revocable);
require(!revoked[token]);
uint256 balance = token.balanceOf(this);
uint256 unreleased = releasableAmount(token);
uint256 refund = balance.sub(unreleased);
revoked[token] = true;
token.safeTransfer(owner, refund);
Revoked();
}
/**
* @dev Calculates the amount that has already vested but hasn't been released yet.
* @param token ERC20 token which is being vested
*/
function releasableAmount(ERC20Basic token) public view returns (uint256) {
return vestedAmount(token).sub(released[token]);
}
/**
* @dev Calculates the amount that has already vested.
* @param token ERC20 token which is being vested
*/
function vestedAmount(ERC20Basic token) public view returns (uint256) {
uint256 currentBalance = token.balanceOf(this);
uint256 totalBalance = currentBalance.add(released[token]);
if (now < cliff) {
return 0;
} else if (now >= start.add(duration) || revoked[token]) {
return totalBalance;
} else {
return totalBalance.mul(now.sub(start)).div(duration);
}
}
}
================================================
FILE: resources/public/contracts/src/VestedToken.sol
================================================
pragma solidity ^0.4.11;
/*
Slightly modified OpenZeppelin Vested Token deriving MiniMeToken
See original at ./orig/VestedToken.sol or https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/VestedToken.sol
Modifications:
- Does not inherit from StandardToken, so transfer functions can be supplied by MiniMe
- Uses SafeMath.sol
- In revokeTokenGrant method instead of manipulating balances manually, calls doTransfer method supplied by MiniMe
- Added revokeAllTokenGrants method
- Added onlyGrantsController modifier to restrict creating grants only to single address
*/
import "./LimitedTransferToken.sol";
import "./SafeMath.sol";
import "./GrantsControlled.sol";
/**
* @title Vested token
* @dev Tokens that can be vested for a group of addresses.
*/
contract VestedToken is LimitedTransferToken, GrantsControlled {
using SafeMath for uint;
uint256 MAX_GRANTS_PER_ADDRESS = 20;
struct TokenGrant {
address granter; // 20 bytes
uint256 value; // 32 bytes
uint64 cliff;
uint64 vesting;
uint64 start; // 3 * 8 = 24 bytes
bool revokable;
bool burnsOnRevoke; // 2 * 1 = 2 bits? or 2 bytes?
} // total 78 bytes = 3 sstore per operation (32 per sstore)
mapping (address => TokenGrant[]) public grants;
event NewTokenGrant(address indexed from, address indexed to, uint256 value, uint256 grantId);
/**
* @dev Grant tokens to a specified address
* @param _to address The address which the tokens will be granted to.
* @param _value uint256 The amount of tokens to be granted.
* @param _start uint64 Time of the beginning of the grant.
* @param _cliff uint64 Time of the cliff period.
* @param _vesting uint64 The vesting period.
*/
function grantVestedTokens(
address _to,
uint256 _value,
uint64 _start,
uint64 _cliff,
uint64 _vesting,
bool _revokable,
bool _burnsOnRevoke
) onlyGrantsController public {
// Check for date inconsistencies that may cause unexpected behavior
if (_cliff < _start || _vesting < _cliff) {
throw;
}
if (tokenGrantsCount(_to) > MAX_GRANTS_PER_ADDRESS) throw; // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).
uint count = grants[_to].push(
TokenGrant(
_revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
_value,
_cliff,
_vesting,
_start,
_revokable,
_burnsOnRevoke
)
);
transfer(_to, _value);
NewTokenGrant(msg.sender, _to, _value, count - 1);
}
/**
* @dev Revoke the grant of tokens of a specifed address.
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
*/
function revokeTokenGrant(address _holder, uint _grantId) public {
TokenGrant grant = grants[_holder][_grantId];
if (!grant.revokable) { // Check if grant was revokable
throw;
}
if (grant.granter != msg.sender) { // Only granter can revoke it
throw;
}
address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;
uint256 nonVested = nonVestedTokens(grant, uint64(now));
// remove grant from array
delete grants[_holder][_grantId];
grants[_holder][_grantId] = grants[_holder][grants[_holder].length.sub(1)];
grants[_holder].length -= 1;
// This will call MiniMe's doTransfer method, so token is transferred according to
// MiniMe Token logic
doTransfer(_holder, receiver, nonVested);
Transfer(_holder, receiver, nonVested);
}
/**
* @dev Revoke all grants of tokens of a specifed address.
* @param _holder The address which will have its tokens revoked.
*/
function revokeAllTokenGrants(address _holder) {
var grandsCount = tokenGrantsCount(_holder);
for (uint i = 0; i < grandsCount; i++) {
revokeTokenGrant(_holder, 0);
}
}
/**
* @dev Calculate the total amount of transferable tokens of a holder at a given time
* @param holder address The address of the holder
* @param time uint64 The specific time.
* @return An uint representing a holder's total amount of transferable tokens.
*/
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
uint256 grantIndex = tokenGrantsCount(holder);
if (grantIndex == 0) return balanceOf(holder); // shortcut for holder without grants
// Iterate through all the grants the holder has, and add all non-vested tokens
uint256 nonVested = 0;
for (uint256 i = 0; i < grantIndex; i++) {
nonVested = SafeMath.add(nonVested, nonVestedTokens(grants[holder][i], time));
}
// Balance - totalNonVested is the amount of tokens a holder can transfer at any given time
uint256 vestedTransferable = SafeMath.sub(balanceOf(holder), nonVested);
// Return the minimum of how many vested can transfer and other value
// in case there are other limiting transferability factors (default is balanceOf)
return SafeMath.min256(vestedTransferable, super.transferableTokens(holder, time));
}
/**
* @dev Check the amount of grants that an address has.
* @param _holder The holder of the grants.
* @return A uint representing the total amount of grants.
*/
function tokenGrantsCount(address _holder) constant returns (uint index) {
return grants[_holder].length;
}
/**
* @dev Calculate amount of vested tokens at a specifc time.
* @param tokens uint256 The amount of tokens grantted.
* @param time uint64 The time to be checked
* @param start uint64 A time representing the begining of the grant
* @param cliff uint64 The cliff period.
* @param vesting uint64 The vesting period.
* @return An uint representing the amount of vested tokensof a specif grant.
* transferableTokens
* | _/-------- vestedTokens rect
* | _/
* | _/
* | _/
* | _/
* | /
* | .|
* | . |
* | . |
* | . |
* | . |
* | . |
* +===+===========+---------+----------> time
* Start Clift Vesting
*/
function calculateVestedTokens(
uint256 tokens,
uint256 time,
uint256 start,
uint256 cliff,
uint256 vesting) constant returns (uint256)
{
// Shortcuts for before cliff and after vesting cases.
if (time < cliff) return 0;
if (time >= vesting) return tokens;
// Interpolate all vested tokens.
// As before cliff the shortcut returns 0, we can use just calculate a value
// in the vesting rect (as shown in above's figure)
// vestedTokens = tokens * (time - start) / (vesting - start)
uint256 vestedTokens = SafeMath.div(
SafeMath.mul(
tokens,
SafeMath.sub(time, start)
),
SafeMath.sub(vesting, start)
);
return vestedTokens;
}
/**
* @dev Get all information about a specifc grant.
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
* @return Returns all the values that represent a TokenGrant(address, value, start, cliff,
* revokability, burnsOnRevoke, and vesting) plus the vested value at the current time.
*/
function tokenGrant(address _holder, uint _grantId) constant returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
TokenGrant grant = grants[_holder][_grantId];
granter = grant.granter;
value = grant.value;
start = grant.start;
cliff = grant.cliff;
vesting = grant.vesting;
revokable = grant.revokable;
burnsOnRevoke = grant.burnsOnRevoke;
vested = vestedTokens(grant, uint64(now));
}
/**
* @dev Get the amount of vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time The time to be checked
* @return An uint representing the amount of vested tokens of a specific grant at a specific time.
*/
function vestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return calculateVestedTokens(
grant.value,
uint256(time),
uint256(grant.start),
uint256(grant.cliff),
uint256(grant.vesting)
);
}
/**
* @dev Calculate the amount of non vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time uint64 The time to be checked
* @return An uint representing the amount of non vested tokens of a specifc grant on the
* passed time frame.
*/
function nonVestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return grant.value.sub(vestedTokens(grant, time));
}
/**
* @dev Calculate the date when the holder can trasfer all its tokens
* @param holder address The address of the holder
* @return An uint representing the date of the last transferable tokens.
*/
function lastTokenIsTransferableDate(address holder) constant public returns (uint64 date) {
date = uint64(now);
uint256 grantIndex = grants[holder].length;
for (uint256 i = 0; i < grantIndex; i++) {
date = SafeMath.max64(grants[holder][i].vesting, date);
}
}
}
================================================
FILE: resources/public/contracts/src/math/SafeMath.sol
================================================
pragma solidity ^0.4.18;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
================================================
FILE: resources/public/contracts/src/minime_interface/ApproveAndCallFallback.sol
================================================
pragma solidity ^0.4.11;
/*
Copyright 2017, Jordi Baylina (Giveth)
*/
contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 _amount, address _token, bytes _data);
}
================================================
FILE: resources/public/contracts/src/minime_interface/Controlled.sol
================================================
pragma solidity ^0.4.11;
/*
Copyright 2017, Jorge Izquierdo (Aragon Foundation)
Copyright 2017, Jordi Baylina (Giveth)
Based on MiniMeToken.sol from https://github.com/Giveth/minime
*/
contract Controlled {
/// @notice The address of the controller is the only address that can call
/// a function with this modifier
modifier onlyController { if (msg.sender != controller) throw; _; }
address public controller;
function Controlled() { controller = msg.sender;}
/// @notice Changes the controller of the contract
/// @param _newController The new controller of the contract
function changeController(address _newController) onlyController {
controller = _newController;
}
}
================================================
FILE: resources/public/contracts/src/minime_interface/TokenController.sol
================================================
pragma solidity ^0.4.11;
/// @dev The token controller contract must implement these functions
contract TokenController {
/// @notice Called when `_owner` sends ether to the MiniMe Token contract
/// @param _owner The address that sent the ether to create tokens
/// @return True if the ether is accepted, false if it throws
function proxyPayment(address _owner) payable returns(bool);
/// @notice Notifies the controller about a token transfer allowing the
/// controller to react if desired
/// @param _from The origin of the transfer
/// @param _to The destination of the transfer
/// @param _amount The amount of the transfer
/// @return False if the controller does not authorize the transfer
function onTransfer(address _from, address _to, uint _amount) returns(bool);
/// @notice Notifies the controller about an approval allowing the
/// controller to react if desired
/// @param _owner The address that calls `approve()`
/// @param _spender The spender in the `approve()` call
/// @param _amount The amount in the `approve()` call
/// @return False if the controller does not authorize the approval
function onApprove(address _owner, address _spender, uint _amount)
returns(bool);
}
================================================
FILE: resources/public/contracts/src/orig/ERC20.sol
================================================
pragma solidity ^0.4.11;
import './ERC20Basic.sol';
/*
* ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) constant returns (uint);
function transferFrom(address from, address to, uint value) returns (bool);
function approve(address spender, uint value) returns (bool);
function approveAndCall(address spender, uint256 value, bytes extraData) returns (bool);
event Approval(address indexed owner, address indexed spender, uint value);
}
================================================
FILE: resources/public/contracts/src/orig/LimitedTransferToken.sol
================================================
pragma solidity ^0.4.11;
import "./ERC20.sol";
/*
LimitedTransferToken defines the generic interface and the implementation
to limit token transferability for different events.
It is intended to be used as a base class for other token contracts.
Overwriting transferableTokens(address holder, uint64 time) is the way to provide
the specific logic for limiting token transferability for a holder over time.
LimitedTransferToken has been designed to allow for different limiting factors,
this can be achieved by recursively calling super.transferableTokens() until the
base class is hit. For example:
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
return min256(unlockedTokens, super.transferableTokens(holder, time));
}
A working example is VestedToken.sol:
https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/VestedToken.sol
Made by OpenZeppelin https://raw.githubusercontent.com/OpenZeppelin/zeppelin-solidity/master/contracts/token/LimitedTransferToken.sol
*/
contract LimitedTransferToken is ERC20 {
// Checks whether it can transfer or otherwise throws.
modifier canTransfer(address _sender, uint _value) {
if (_value > transferableTokens(_sender, uint64(now))) throw;
_;
}
// Checks modifier and allows transfer if tokens are not locked.
function transfer(address _to, uint _value) canTransfer(msg.sender, _value) {
return super.transfer(_to, _value);
}
// Checks modifier and allows transfer if tokens are not locked.
function transferFrom(address _from, address _to, uint _value) canTransfer(_from, _value) {
return super.transferFrom(_from, _to, _value);
}
// Default transferable tokens function returns all tokens for a holder (no limit).
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
return balanceOf(holder);
}
}
================================================
FILE: resources/public/contracts/src/orig/MiniMeToken.sol
================================================
pragma solidity ^0.4.6;
/*
Copyright 2016, Jordi Baylina
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/// @title MiniMeToken Contract
/// @author Jordi Baylina
/// @dev This token contract's goal is to make it easy for anyone to clone this
/// token using the token distribution at a given block, this will allow DAO's
/// and DApps to upgrade their features in a decentralized manner without
/// affecting the original token
/// @dev It is ERC20 compliant, but still needs to under go further testing.
/// @dev The token controller contract must implement these functions
contract TokenController {
/// @notice Called when `_owner` sends ether to the MiniMe Token contract
/// @param _owner The address that sent the ether to create tokens
/// @return True if the ether is accepted, false if it throws
function proxyPayment(address _owner) payable returns(bool);
/// @notice Notifies the controller about a token transfer allowing the
/// controller to react if desired
/// @param _from The origin of the transfer
/// @param _to The destination of the transfer
/// @param _amount The amount of the transfer
/// @return False if the controller does not authorize the transfer
function onTransfer(address _from, address _to, uint _amount) returns(bool);
/// @notice Notifies the controller about an approval allowing the
/// controller to react if desired
/// @param _owner The address that calls `approve()`
/// @param _spender The spender in the `approve()` call
/// @param _amount The amount in the `approve()` call
/// @return False if the controller does not authorize the approval
function onApprove(address _owner, address _spender, uint _amount)
returns(bool);
}
contract Controlled {
/// @notice The address of the controller is the only address that can call
/// a function with this modifier
modifier onlyController { if (msg.sender != controller) throw; _; }
address public controller;
function Controlled() { controller = msg.sender;}
/// @notice Changes the controller of the contract
/// @param _newController The new controller of the contract
function changeController(address _newController) onlyController {
controller = _newController;
}
}
contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 _amount, address _token, bytes _data);
}
/// @dev The actual token contract, the default controller is the msg.sender
/// that deploys the contract, so usually this token will be deployed by a
/// token controller contract, which Giveth will call a "Campaign"
contract MiniMeToken is Controlled {
string public name; //The Token's name: e.g. DigixDAO Tokens
uint8 public decimals; //Number of decimals of the smallest unit
string public symbol; //An identifier: e.g. REP
string public version = 'MMT_0.1'; //An arbitrary versioning scheme
/// @dev `Checkpoint` is the structure that attaches a block number to a
/// given value, the block number attached is the one that last changed the
/// value
struct Checkpoint {
// `fromBlock` is the block number that the value was generated from
uint128 fromBlock;
// `value` is the amount of tokens at a specific block number
uint128 value;
}
// `parentToken` is the Token address that was cloned to produce this token;
// it will be 0x0 for a token that was not cloned
MiniMeToken public parentToken;
// `parentSnapShotBlock` is the block number from the Parent Token that was
// used to determine the initial distribution of the Clone Token
uint public parentSnapShotBlock;
// `creationBlock` is the block number that the Clone Token was created
uint public creationBlock;
// `balances` is the map that tracks the balance of each address, in this
// contract when the balance changes the block number that the change
// occurred is also included in the map
mapping (address => Checkpoint[]) balances;
// `allowed` tracks any extra transfer rights as in all ERC20 tokens
mapping (address => mapping (address => uint256)) allowed;
// Tracks the history of the `totalSupply` of the token
Checkpoint[] totalSupplyHistory;
// Flag that determines if the token is transferable or not.
bool public transfersEnabled;
// The factory used to create new clone tokens
MiniMeTokenFactory public tokenFactory;
////////////////
// Constructor
////////////////
/// @notice Constructor to create a MiniMeToken
/// @param _tokenFactory The address of the MiniMeTokenFactory contract that
/// will create the Clone token contracts, the token factory needs to be
/// deployed first
/// @param _parentToken Address of the parent token, set to 0x0 if it is a
/// new token
/// @param _parentSnapShotBlock Block of the parent token that will
/// determine the initial distribution of the clone token, set to 0 if it
/// is a new token
/// @param _tokenName Name of the new token
/// @param _decimalUnits Number of decimals of the new token
/// @param _tokenSymbol Token Symbol for the new token
/// @param _transfersEnabled If true, tokens will be able to be transferred
function MiniMeToken(
address _tokenFactory,
address _parentToken,
uint _parentSnapShotBlock,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
bool _transfersEnabled
) {
tokenFactory = MiniMeTokenFactory(_tokenFactory);
name = _tokenName; // Set the name
decimals = _decimalUnits; // Set the decimals
symbol = _tokenSymbol; // Set the symbol
parentToken = MiniMeToken(_parentToken);
parentSnapShotBlock = _parentSnapShotBlock;
transfersEnabled = _transfersEnabled;
creationBlock = block.number;
}
///////////////////
// ERC20 Methods
///////////////////
/// @notice Send `_amount` tokens to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint256 _amount) returns (bool success) {
if (!transfersEnabled) throw;
return doTransfer(msg.sender, _to, _amount);
}
/// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
/// is approved by `_from`
/// @param _from The address holding the tokens being transferred
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return True if the transfer was successful
function transferFrom(address _from, address _to, uint256 _amount
) returns (bool success) {
// The controller of this contract can move tokens around at will,
// this is important to recognize! Confirm that you trust the
// controller of this contract, which in most situations should be
// another open source smart contract or 0x0
if (msg.sender != controller) {
if (!transfersEnabled) throw;
// The standard ERC 20 transferFrom functionality
if (allowed[_from][msg.sender] < _amount) return false;
allowed[_from][msg.sender] -= _amount;
}
return doTransfer(_from, _to, _amount);
}
/// @dev This is the actual transfer function in the token contract, it can
/// only be called by other functions in this contract.
/// @param _from The address holding the tokens being transferred
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return True if the transfer was successful
function doTransfer(address _from, address _to, uint _amount
) internal returns(bool) {
if (_amount == 0) {
return true;
}
if (parentSnapShotBlock >= block.number) throw;
// Do not allow transfer to 0x0 or the token contract itself
if ((_to == 0) || (_to == address(this))) throw;
// If the amount being transfered is more than the balance of the
// account the transfer returns false
var previousBalanceFrom = balanceOfAt(_from, block.number);
if (previousBalanceFrom < _amount) {
return false;
}
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
throw;
}
// First update the balance array with the new value for the address
// sending the tokens
updateValueAtNow(balances[_from], previousBalanceFrom - _amount);
// Then update the balance array with the new value for the address
// receiving the tokens
var previousBalanceTo = balanceOfAt(_to, block.number);
if (previousBalanceTo + _amount < previousBalanceTo) throw; // Check for overflow
updateValueAtNow(balances[_to], previousBalanceTo + _amount);
// An event to make the transfer easy to find on the blockchain
Transfer(_from, _to, _amount);
return true;
}
/// @param _owner The address that's balance is being requested
/// @return The balance of `_owner` at the current block
function balanceOf(address _owner) constant returns (uint256 balance) {
return balanceOfAt(_owner, block.number);
}
/// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
/// its behalf. This is a modified version of the ERC20 approve function
/// to be a little bit safer
/// @param _spender The address of the account able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the approval was successful
function approve(address _spender, uint256 _amount) returns (bool success) {
if (!transfersEnabled) throw;
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender,0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
if ((_amount!=0) && (allowed[msg.sender][_spender] !=0)) throw;
// Alerts the token controller of the approve function call
if (isContract(controller)) {
if (!TokenController(controller).onApprove(msg.sender, _spender, _amount))
throw;
}
allowed[msg.sender][_spender] = _amount;
Approval(msg.sender, _spender, _amount);
return true;
}
/// @dev This function makes it easy to read the `allowed[]` map
/// @param _owner The address of the account that owns the token
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens of _owner that _spender is allowed
/// to spend
function allowance(address _owner, address _spender
) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
/// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
/// its behalf, and then a function is triggered in the contract that is
/// being approved, `_spender`. This allows users to use their tokens to
/// interact with contracts in one function call instead of two
/// @param _spender The address of the contract able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the function call was successful
function approveAndCall(address _spender, uint256 _amount, bytes _extraData
) returns (bool success) {
if (!approve(_spender, _amount)) throw;
ApproveAndCallFallBack(_spender).receiveApproval(
msg.sender,
_amount,
this,
_extraData
);
return true;
}
/// @dev This function makes it easy to get the total number of tokens
/// @return The total number of tokens
function totalSupply() constant returns (uint) {
return totalSupplyAt(block.number);
}
////////////////
// Query balance and totalSupply in History
////////////////
/// @dev Queries the balance of `_owner` at a specific `_blockNumber`
/// @param _owner The address from which the balance will be retrieved
/// @param _blockNumber The block number when the balance is queried
/// @return The balance at `_blockNumber`
function balanceOfAt(address _owner, uint _blockNumber) constant
returns (uint) {
// These next few lines are used when the balance of the token is
// requested before a check point was ever created for this token, it
// requires that the `parentToken.balanceOfAt` be queried at the
// genesis block for that token as this contains initial balance of
// this token
if ((balances[_owner].length == 0)
|| (balances[_owner][0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
} else {
// Has no parent
return 0;
}
// This will return the expected balance during normal situations
} else {
return getValueAt(balances[_owner], _blockNumber);
}
}
/// @notice Total amount of tokens at a specific `_blockNumber`.
/// @param _blockNumber The block number when the totalSupply is queried
/// @return The total amount of tokens at `_blockNumber`
function totalSupplyAt(uint _blockNumber) constant returns(uint) {
// These next few lines are used when the totalSupply of the token is
// requested before a check point was ever created for this token, it
// requires that the `parentToken.totalSupplyAt` be queried at the
// genesis block for this token as that contains totalSupply of this
// token at this block number.
if ((totalSupplyHistory.length == 0)
|| (totalSupplyHistory[0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
} else {
return 0;
}
// This will return the expected totalSupply during normal situations
} else {
return getValueAt(totalSupplyHistory, _blockNumber);
}
}
////////////////
// Clone Token Method
////////////////
/// @notice Creates a new clone token with the initial distribution being
/// this token at `_snapshotBlock`
/// @param _cloneTokenName Name of the clone token
/// @param _cloneDecimalUnits Number of decimals of the smallest unit
/// @param _cloneTokenSymbol Symbol of the clone token
/// @param _snapshotBlock Block when the distribution of the parent token is
/// copied to set the initial distribution of the new clone token;
/// if the block is zero than the actual block, the current block is used
/// @param _transfersEnabled True if transfers are allowed in the clone
/// @return The address of the new MiniMeToken Contract
function createCloneToken(
string _cloneTokenName,
uint8 _cloneDecimalUnits,
string _cloneTokenSymbol,
uint _snapshotBlock,
bool _transfersEnabled
) returns(address) {
if (_snapshotBlock == 0) _snapshotBlock = block.number;
MiniMeToken cloneToken = tokenFactory.createCloneToken(
this,
_snapshotBlock,
_cloneTokenName,
_cloneDecimalUnits,
_cloneTokenSymbol,
_transfersEnabled
);
cloneToken.changeController(msg.sender);
// An event to make the token easy to find on the blockchain
NewCloneToken(address(cloneToken), _snapshotBlock);
return address(cloneToken);
}
////////////////
// Generate and destroy tokens
////////////////
/// @notice Generates `_amount` tokens that are assigned to `_owner`
/// @param _owner The address that will be assigned the new tokens
/// @param _amount The quantity of tokens generated
/// @return True if the tokens are generated correctly
function generateTokens(address _owner, uint _amount
) onlyController returns (bool) {
uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
if (curTotalSupply + _amount < curTotalSupply) throw; // Check for overflow
updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount);
var previousBalanceTo = balanceOf(_owner);
if (previousBalanceTo + _amount < previousBalanceTo) throw; // Check for overflow
updateValueAtNow(balances[_owner], previousBalanceTo + _amount);
Transfer(0, _owner, _amount);
return true;
}
/// @notice Burns `_amount` tokens from `_owner`
/// @param _owner The address that will lose the tokens
/// @param _amount The quantity of tokens to burn
/// @return True if the tokens are burned correctly
function destroyTokens(address _owner, uint _amount
) onlyController returns (bool) {
uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
if (curTotalSupply < _amount) throw;
updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount);
var previousBalanceFrom = balanceOf(_owner);
if (previousBalanceFrom < _amount) throw;
updateValueAtNow(balances[_owner], previousBalanceFrom - _amount);
Transfer(_owner, 0, _amount);
return true;
}
////////////////
// Enable tokens transfers
////////////////
/// @notice Enables token holders to transfer their tokens freely if true
/// @param _transfersEnabled True if transfers are allowed in the clone
function enableTransfers(bool _transfersEnabled) onlyController {
transfersEnabled = _transfersEnabled;
}
////////////////
// Internal helper functions to query and set a value in a snapshot array
////////////////
/// @dev `getValueAt` retrieves the number of tokens at a given block number
/// @param checkpoints The history of values being queried
/// @param _block The block number to retrieve the value at
/// @return The number of tokens being queried
function getValueAt(Checkpoint[] storage checkpoints, uint _block
) constant internal returns (uint) {
if (checkpoints.length == 0) return 0;
// Shortcut for the actual value
if (_block >= checkpoints[checkpoints.length-1].fromBlock)
return checkpoints[checkpoints.length-1].value;
if (_block < checkpoints[0].fromBlock) return 0;
// Binary search of the value in the array
uint min = 0;
uint max = checkpoints.length-1;
while (max > min) {
uint mid = (max + min + 1)/ 2;
if (checkpoints[mid].fromBlock<=_block) {
min = mid;
} else {
max = mid-1;
}
}
return checkpoints[min].value;
}
/// @dev `updateValueAtNow` used to update the `balances` map and the
/// `totalSupplyHistory`
/// @param checkpoints The history of data being updated
/// @param _value The new number of tokens
function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value
) internal {
if ((checkpoints.length == 0)
|| (checkpoints[checkpoints.length -1].fromBlock < block.number)) {
Checkpoint newCheckPoint = checkpoints[ checkpoints.length++ ];
newCheckPoint.fromBlock = uint128(block.number);
newCheckPoint.value = uint128(_value);
} else {
Checkpoint oldCheckPoint = checkpoints[checkpoints.length-1];
oldCheckPoint.value = uint128(_value);
}
}
/// @dev Internal function to determine if an address is a contract
/// @param _addr The address being queried
/// @return True if `_addr` is a contract
function isContract(address _addr) constant internal returns(bool) {
uint size;
if (_addr == 0) return false;
assembly {
size := extcodesize(_addr)
}
return size>0;
}
/// @dev Helper function to return a min betwen the two uints
function min(uint a, uint b) internal returns (uint) {
return a < b ? a : b;
}
/// @notice The fallback function: If the contract's controller has not been
/// set to 0, then the `proxyPayment` method is called which relays the
/// ether and creates tokens as described in the token controller contract
function () payable {
if (isContract(controller)) {
if (! TokenController(controller).proxyPayment.value(msg.value)(msg.sender))
throw;
} else {
throw;
}
}
////////////////
// Events
////////////////
event Transfer(address indexed _from, address indexed _to, uint256 _amount);
event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _amount
);
}
////////////////
// MiniMeTokenFactory
////////////////
/// @dev This contract is used to generate clone contracts from a contract.
/// In solidity this is the way to create a contract from a contract of the
/// same class
contract MiniMeTokenFactory {
/// @notice Update the DApp by creating a new token with new functionalities
/// the msg.sender becomes the controller of this clone token
/// @param _parentToken Address of the token being cloned
/// @param _snapshotBlock Block of the parent token that will
/// determine the initial distribution of the clone token
/// @param _tokenName Name of the new token
/// @param _decimalUnits Number of decimals of the new token
/// @param _tokenSymbol Token Symbol for the new token
/// @param _transfersEnabled If true, tokens will be able to be transferred
/// @return The address of the new token contract
function createCloneToken(
address _parentToken,
uint _snapshotBlock,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
bool _transfersEnabled
) returns (MiniMeToken) {
MiniMeToken newToken = new MiniMeToken(
this,
_parentToken,
_snapshotBlock,
_tokenName,
_decimalUnits,
_tokenSymbol,
_transfersEnabled
);
newToken.changeController(msg.sender);
return newToken;
}
}
================================================
FILE: resources/public/contracts/src/orig/VestedToken.sol
================================================
pragma solidity ^0.4.11;
import "./StandardToken.sol";
import "./LimitedTransferToken.sol";
/**
* @title Vested token
* @dev Tokens that can be vested for a group of addresses.
*/
contract VestedToken is StandardToken, LimitedTransferToken {
uint256 MAX_GRANTS_PER_ADDRESS = 20;
struct TokenGrant {
address granter; // 20 bytes
uint256 value; // 32 bytes
uint64 cliff;
uint64 vesting;
uint64 start; // 3 * 8 = 24 bytes
bool revokable;
bool burnsOnRevoke; // 2 * 1 = 2 bits? or 2 bytes?
} // total 78 bytes = 3 sstore per operation (32 per sstore)
mapping (address => TokenGrant[]) public grants;
event NewTokenGrant(address indexed from, address indexed to, uint256 value, uint256 grantId);
/**
* @dev Grant tokens to a specified address
* @param _to address The address which the tokens will be granted to.
* @param _value uint256 The amount of tokens to be granted.
* @param _start uint64 Time of the beginning of the grant.
* @param _cliff uint64 Time of the cliff period.
* @param _vesting uint64 The vesting period.
*/
function grantVestedTokens(
address _to,
uint256 _value,
uint64 _start,
uint64 _cliff,
uint64 _vesting,
bool _revokable,
bool _burnsOnRevoke
) public {
// Check for date inconsistencies that may cause unexpected behavior
if (_cliff < _start || _vesting < _cliff) {
throw;
}
if (tokenGrantsCount(_to) > MAX_GRANTS_PER_ADDRESS) throw; // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).
uint count = grants[_to].push(
TokenGrant(
_revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
_value,
_cliff,
_vesting,
_start,
_revokable,
_burnsOnRevoke
)
);
transfer(_to, _value);
NewTokenGrant(msg.sender, _to, _value, count - 1);
}
/**
* @dev Revoke the grant of tokens of a specifed address.
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
*/
function revokeTokenGrant(address _holder, uint _grantId) public {
TokenGrant grant = grants[_holder][_grantId];
if (!grant.revokable) { // Check if grant was revokable
throw;
}
if (grant.granter != msg.sender) { // Only granter can revoke it
throw;
}
address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;
uint256 nonVested = nonVestedTokens(grant, uint64(now));
// remove grant from array
delete grants[_holder][_grantId];
grants[_holder][_grantId] = grants[_holder][grants[_holder].length.sub(1)];
grants[_holder].length -= 1;
balances[receiver] = balances[receiver].add(nonVested);
balances[_holder] = balances[_holder].sub(nonVested);
Transfer(_holder, receiver, nonVested);
}
/**
* @dev Calculate the total amount of transferable tokens of a holder at a given time
* @param holder address The address of the holder
* @param time uint64 The specific time.
* @return An uint representing a holder's total amount of transferable tokens.
*/
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
uint256 grantIndex = tokenGrantsCount(holder);
if (grantIndex == 0) return balanceOf(holder); // shortcut for holder without grants
// Iterate through all the grants the holder has, and add all non-vested tokens
uint256 nonVested = 0;
for (uint256 i = 0; i < grantIndex; i++) {
nonVested = SafeMath.add(nonVested, nonVestedTokens(grants[holder][i], time));
}
// Balance - totalNonVested is the amount of tokens a holder can transfer at any given time
uint256 vestedTransferable = SafeMath.sub(balanceOf(holder), nonVested);
// Return the minimum of how many vested can transfer and other value
// in case there are other limiting transferability factors (default is balanceOf)
return SafeMath.min256(vestedTransferable, super.transferableTokens(holder, time));
}
/**
* @dev Check the amount of grants that an address has.
* @param _holder The holder of the grants.
* @return A uint representing the total amount of grants.
*/
function tokenGrantsCount(address _holder) constant returns (uint index) {
return grants[_holder].length;
}
/**
* @dev Calculate amount of vested tokens at a specifc time.
* @param tokens uint256 The amount of tokens grantted.
* @param time uint64 The time to be checked
* @param start uint64 A time representing the begining of the grant
* @param cliff uint64 The cliff period.
* @param vesting uint64 The vesting period.
* @return An uint representing the amount of vested tokensof a specif grant.
* transferableTokens
* | _/-------- vestedTokens rect
* | _/
* | _/
* | _/
* | _/
* | /
* | .|
* | . |
* | . |
* | . |
* | . |
* | . |
* +===+===========+---------+----------> time
* Start Clift Vesting
*/
function calculateVestedTokens(
uint256 tokens,
uint256 time,
uint256 start,
uint256 cliff,
uint256 vesting) constant returns (uint256)
{
// Shortcuts for before cliff and after vesting cases.
if (time < cliff) return 0;
if (time >= vesting) return tokens;
// Interpolate all vested tokens.
// As before cliff the shortcut returns 0, we can use just calculate a value
// in the vesting rect (as shown in above's figure)
// vestedTokens = tokens * (time - start) / (vesting - start)
uint256 vestedTokens = SafeMath.div(
SafeMath.mul(
tokens,
SafeMath.sub(time, start)
),
SafeMath.sub(vesting, start)
);
return vestedTokens;
}
/**
* @dev Get all information about a specifc grant.
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
* @return Returns all the values that represent a TokenGrant(address, value, start, cliff,
* revokability, burnsOnRevoke, and vesting) plus the vested value at the current time.
*/
function tokenGrant(address _holder, uint _grantId) constant returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
TokenGrant grant = grants[_holder][_grantId];
granter = grant.granter;
value = grant.value;
start = grant.start;
cliff = grant.cliff;
vesting = grant.vesting;
revokable = grant.revokable;
burnsOnRevoke = grant.burnsOnRevoke;
vested = vestedTokens(grant, uint64(now));
}
/**
* @dev Get the amount of vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time The time to be checked
* @return An uint representing the amount of vested tokens of a specific grant at a specific time.
*/
function vestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return calculateVestedTokens(
grant.value,
uint256(time),
uint256(grant.start),
uint256(grant.cliff),
uint256(grant.vesting)
);
}
/**
* @dev Calculate the amount of non vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time uint64 The time to be checked
* @return An uint representing the amount of non vested tokens of a specifc grant on the
* passed time frame.
*/
function nonVestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return grant.value.sub(vestedTokens(grant, time));
}
/**
* @dev Calculate the date when the holder can trasfer all its tokens
* @param holder address The address of the holder
* @return An uint representing the date of the last transferable tokens.
*/
function lastTokenIsTransferableDate(address holder) constant public returns (uint64 date) {
date = uint64(now);
uint256 grantIndex = grants[holder].length;
for (uint256 i = 0; i < grantIndex; i++) {
date = SafeMath.max64(grants[holder][i].vesting, date);
}
}
}
================================================
FILE: resources/public/contracts/src/ownership/Ownable.sol
================================================
pragma solidity ^0.4.18;
/**
* @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.
*/
function Ownable() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @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));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
================================================
FILE: resources/public/index.html
================================================
district0x Contribution Page
================================================
FILE: resources/public/less/district0x.main.less
================================================
@import (inline) "cljsjs/react-flexbox-grid/production/react-flexbox-grid.min.inc.css";
@font-face {
font-family: ProximaNovaSoft;
src: url("../fonts/ProximaNovaSoft-Regular.otf") format("opentype");
}
@font-face {
font-family: ProximaNovaSoft;
font-weight: bold;
src: url("../fonts/ProximaNovaSoft-Semibold.otf") format("opentype");
}
html, body, #app {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
-webkit-text-size-adjust: 100%;
}
a {
color: inherit;
text-decoration: none;
}
a.no-decor {
color: inherit !important;
}
a.hoverable:hover {
text-decoration: underline;
}
a.no-decor:hover {
text-decoration: none;
}
html {
font-family: 'proxima-soft', sans-serif;
-webkit-font-smoothing: antialiased;
}
body {
background-color: #fff;
}
body, h1, h2, h3, h4, h5, h6 {
margin: 0;
}
h1, h2, h3 {
font-weight: 300 !important;
line-height: 1.2em;
word-break: break-word;
}
h1.bolder, h2.bolder, h3.bolder {
font-weight: 400 !important;
}
.black {
color: #000;
}
.white {
color: #FFF;
}
h3 {
line-height: 1.4em;
}
body {
font-size: 15px;
//line-height: 24px;
}
strong, b {
font-weight: 600;
}
.sm-visible, .md-visible, .lg-visible {
display: none;
}
@media only screen and (min-width:48em) {
.sm-visible {
display: block;
}
.sm-margin-0 {
margin: 0;
}
.sm-margin-top-0 {
margin-top: 0 !important;
}
}
@media only screen and (min-width:64em) {
.md-visible {
display: block;
}
.md-margin-0 {
margin: 0;
}
}
@media only screen and (min-width:75em) {
.lg-visible {
display: block;
}
.lg-margin-0 {
margin: 0;
}
}
.icon svg path {
color: "#FFF";
fill: "#FFF";
}
================================================
FILE: src/cljs/contribution/api.cljs
================================================
(ns contribution.api
(:require [district0x.big-number :as bn]
[cljs-web3.core :as web3]
[cljs-time.core :as t]))
(def big-num->ether (comp bn/->number #(web3/from-wei % :ether)))
(defn parse-get-contrib-period [[bool-vals uint-vals]]
(let [[enabled? soft-cap-reached? hard-cap-reached?] bool-vals
[soft-cap-amount after-soft-cap-duration hard-cap-amount start-time end-time total-contributed
contributors-count contrib-period-stake] uint-vals]
{:contrib-period/soft-cap-amount (big-num->ether soft-cap-amount)
:contrib-period/after-soft-cap-duration (bn/->number after-soft-cap-duration)
:contrib-period/hard-cap-amount (big-num->ether hard-cap-amount)
:contrib-period/start-time (bn/->date-time start-time)
:contrib-period/end-time (t/to-default-time-zone (t/plus (cljs-time.core/date-time 2017 7 18 15)
(t/weeks 2))) #_(bn/->date-time end-time)
:contrib-period/enabled? enabled?
:contrib-period/soft-cap-reached? soft-cap-reached?
:contrib-period/hard-cap-reached? hard-cap-reached?
:contrib-period/total-contributed (big-num->ether total-contributed)
:contrib-period/contributors-count (bn/->number contributors-count)
:contrib-period/stake (big-num->ether contrib-period-stake)}))
(defn contrib-period-args [contrib-period]
((juxt :contrib-period/soft-cap-amount
:contrib-period/after-soft-cap-duration
:contrib-period/hard-cap-amount
:contrib-period/start-time
:contrib-period/end-time)
contrib-period))
(defn parse-get-configuration [[stopped? wallet founder1 founder2 early-sponsor advisers transfers-enabled?
max-gas-price]]
{:contribution/stopped? stopped?
:contribution/wallet wallet
:contribution/founder1 founder1
:contribution/founder2 founder2
:contribution/early-sponsor early-sponsor
:contribution/advisers advisers
:dnt-token/transfers-enabled? transfers-enabled?
:contribution/max-gas-price (bn/->number max-gas-price)})
================================================
FILE: src/cljs/contribution/components/main_panel.cljs
================================================
(ns contribution.components.main-panel
(:require
[cljs-react-material-ui.core :refer [get-mui-theme]]
[cljs-react-material-ui.reagent :as ui]
[cljs-time.core :as t]
[clojure.set :as set]
[contribution.constants :as constants]
[contribution.styles :as styles]
[district0x.components.active-address-select-field :refer [active-address-select-field]]
[district0x.components.misc :as misc :refer [row row-with-cols col center-layout etherscan-link]]
[district0x.components.utils :refer [create-with-default-props parse-props-children]]
[district0x.utils :as u]
[medley.core :as medley]
[re-frame.core :refer [subscribe dispatch]]
[reagent.core :as r]
[cljs-web3.core :as web3]))
(def paper (create-with-default-props misc/paper {:style styles/paper}))
(defn contracts-not-found-page []
[center-layout
[paper
[row
{:center "xs"
:middle "xs"
:style {:min-height "400px"}}
[:h3 "We couldn't find district0x Contribution smart contracts." [:br]
"Your MetaMask Chrome extension is most likely not pointed to Ethereum Mainnet, please check."]]]])
(defn app-bar-right-elements []
(let [active-address-balance-eth (subscribe [:district0x/active-address-balance :eth])
active-address-balance-dnt (subscribe [:district0x/active-address-balance :dnt])
connection-error? (subscribe [:district0x/blockchain-connection-error?])
my-addresses (subscribe [:district0x/my-addresses])
contracts-not-found? (subscribe [:district0x/contracts-not-found?])]
(fn []
(when-not @connection-error?
[row
{:middle "xs"
:end "xs"}
(when (and (seq @my-addresses)
@active-address-balance-dnt)
[:h2.bolder {:style (merge styles/app-bar-balance
{:margin-right 10})}
(u/format-dnt-with-symbol @active-address-balance-dnt)])
(when (and (seq @my-addresses)
@active-address-balance-eth)
[:h2.bolder {:style (merge styles/app-bar-balance
{:margin-right 20})}
(u/format-eth-with-symbol @active-address-balance-eth)])
[active-address-select-field
{:select-field-props {:style styles/active-address-select-field
:label-style styles/active-address-select-field-label
:underline-style {:border-color styles/theme-blue}}
:single-address-props {:style styles/active-address-single}}]]))))
(defn info-line [props & children]
(let [[props children] (parse-props-children props children)]
[:div
props
[:b
{:style {:color styles/theme-cyan}}
(first children)] " "
(into
[:span]
(rest children))]))
(defn admin-panel []
(let [can-see-admin-panel? (subscribe [:db/can-see-admin-panel?])
contrib-period (subscribe [:contribution/contrib-period])
enable-contrib-form (subscribe [:form.contribution/enable-contrib-period])
contrib-config (subscribe [:contribution/configuration])
contrib-period-status (subscribe [:contribution/current-contrib-period-status])
contrib-contract-dnt-balance (subscribe [:contribution/dnt-balance])]
(fn []
(let [{:keys [:contrib-period/start-time :contrib-period/end-time
:contrib-period/soft-cap-amount :contrib-period/after-soft-cap-duration
:contrib-period/hard-cap-amount :contrib-period/enabled?
:contrib-period/stake :contrib-period/soft-cap-reached? :contrib-period/total-contributed
:contrib-period/hard-cap-reached? :contrib-period/contributors-count]} @contrib-period
{:keys [:loading?]} @enable-contrib-form
{:keys [:contribution/stopped? :contribution/founder1 :contribution/founder2
:contribution/early-sponsor :contribution/wallet :contribution/advisers
:contribution-address dnt-token-address :dnt-token/transfers-enabled?]} @contrib-config]
(when @can-see-admin-panel?
[paper
[row-with-cols
[col
{:xs 12}
[:h1
{:style (merge styles/margin-bottom-gutter styles/text-center)}
"Admin Panel"]]
[col
{:xs 12
:style styles/margin-bottom-gutter}
[info-line "Contribution Contract:" [etherscan-link {:address contribution-address}]]
[info-line "DNT Token Contract:" [etherscan-link {:address dnt-token-address}]]
[info-line "Founder 1:" [etherscan-link {:address founder1}]]
[info-line "Founder 2:" [etherscan-link {:address founder2}]]
[info-line "Early Sponsor:" [etherscan-link {:address early-sponsor}]]
[info-line "Wallet:" [etherscan-link {:address wallet}]]
(for [[i adviser] (medley/indexed advisers)]
[info-line
{:key i}
(str (when (= adviser (last advisers)) "Community ")
"Adviser " (inc i) ":") [etherscan-link {:address adviser}]])]
(when total-contributed
[col
{:xs 12}
[info-line "Contribution Round:" (inc constants/current-contrib-period)]
[info-line "Start Time:" (u/format-local-datetime start-time)]
[info-line "End Time:" (u/format-local-datetime end-time)]
[info-line "Soft Cap:" (u/format-eth-with-symbol soft-cap-amount)]
[info-line "After Soft Cap Duration:" (t/in-hours (t/seconds after-soft-cap-duration)) " hours"]
[info-line "Hard Cap:" (u/format-eth-with-symbol hard-cap-amount)]
[info-line "Enabled?" (u/bool->yes|no enabled?)]
[info-line "Token Distribution:" (u/format-dnt-with-symbol stake)]
[info-line "Soft Cap Reached?" (u/bool->yes|no soft-cap-reached?)]
[info-line "Hard Cap Reached?" (u/bool->yes|no hard-cap-reached?)]
[info-line "Total Contributed:" (u/format-eth-with-symbol total-contributed)]
[info-line "Contributors Count:" contributors-count]
[info-line "Emergency stop?" (u/bool->yes|no stopped?)]
[info-line "Contribution Contract DNT Balance:" (u/format-dnt-with-symbol @contrib-contract-dnt-balance)]
[info-line "DNT Transfers Enabled?" (u/bool->yes|no transfers-enabled?)]])]])))))
(defn contribution-tile []
(let [xs-sm-width? (subscribe [:district0x/window-xs-sm-width?])]
(fn [{:keys [:title :index]} & children]
[col
{:xs 12 :md 4
:key index
:style {:padding-left 0
:padding-right 0}}
[:div
{:style (merge styles/stats-tile-title
(if @xs-sm-width?
(merge
styles/margin-top-gutter-less
styles/stats-tile-border-bottom
{:margin-right 0 :margin-left 0})
styles/stats-tile-border-bottom))}
title]
(into [row
{:middle "xs"
:center "xs"
:style (merge styles/stats-tile
(when-not (= index 2)
(if @xs-sm-width?
styles/stats-tile-border-bottom
styles/stats-tile-border-right)))}]
children)])))
(def contrib-period-status->countdown-title
{:contrib-period-status/not-started "Starts in"
:contrib-period-status/running "Ends in"
:contrib-period-status/ended "Ended"})
(def unit->name
{:days "day"
:hours "hour"
:minutes "minute"
:seconds "second"})
(defn countdown-time-item [{:keys [:unit :value]}]
[:span
[:h1
{:style (merge styles/contrib-countdown-value
styles/text-left)}
(if (< value 10)
(str 0 value)
value)]
[:span
{:style styles/contrib-countdown-unit}
" " (u/pluralize (unit->name unit) value)]])
(defn- countdown []
(fn [{:keys [:from-time :to-time]}]
(when (and from-time to-time)
(let [{:keys [:days :hours :minutes :seconds]} (u/time-remaining from-time to-time)]
[:div
{:style {:margin-top "-10px"}}
[:div
{:style styles/no-wrap}
[countdown-time-item
{:value days
:unit :days}]
" "
[countdown-time-item
{:value hours
:unit :hours}]]
[:div
{:style styles/no-wrap}
[countdown-time-item
{:value minutes
:unit :minutes}]
" "
[countdown-time-item
{:value seconds
:unit :seconds}]]
[:div
{:style {:margin-top 5}}
(u/format-local-datetime to-time)]]))))
(defn contribution-stats-tiles []
(let [xs-width? (subscribe [:district0x/window-xs-width?])
contrib-period (subscribe [:contribution/contrib-period])
contrib-period-status (subscribe [:contribution/current-contrib-period-status])
now (subscribe [:db/now])]
(fn []
(let [{:keys [:contrib-period/loading? :contrib-period/start-time :contrib-period/end-time
:contrib-period/total-contributed :contrib-period/stake
:contrib-period/contributors-count]} @contrib-period]
[row-with-cols
{:center "xs"}
[col
{:xs 12}
[:h1 {:style (merge styles/margin-bottom-gutter-more
styles/text-center)}
"Contribution Period " (constants/contrib-period->name constants/current-contrib-period)]]
[contribution-tile
{:title (contrib-period-status->countdown-title @contrib-period-status)
:index 0}
(if (and start-time end-time)
(condp = @contrib-period-status
:contrib-period-status/not-started
[countdown
{:from-time @now
:to-time start-time}]
:contrib-period-status/running
[countdown
{:from-time @now
:to-time end-time}]
:contrib-period-status/ended
[:h1 (u/format-local-date end-time)])
[ui/circular-progress])]
[contribution-tile
{:title "Raised"
:index 1}
(if total-contributed
[row
{:middle "xs"
:center "xs"}
[:div
[:h1
{:style styles/stats-tile-amount}
(u/format-metric total-contributed)]
[:span {:style {:font-size "1.2em"}} " ETH"]]
[:h3
{:style styles/stats-tile-amount-subtitle}
contributors-count (u/pluralize " participant" contributors-count)]]
[ui/circular-progress])]
[contribution-tile
{:title "Token Distribution"
:index 2}
(if stake
[:div
[:h1
{:style styles/stats-tile-amount}
(/ stake 1000000) " Mil"]
[:h3
{:style styles/stats-tile-amount-subtitle}
"DNT tokens"]]
[ui/circular-progress])]]))))
(defn contribution-soft-cap-progress []
(let [current-contrib-period (subscribe [:contribution/contrib-period])]
(fn []
(let [{:keys [:contrib-period/total-contributed :contrib-period/soft-cap-amount
:contrib-period/after-soft-cap-duration :contrib-period/hard-cap-amount]} @current-contrib-period]
(when (and total-contributed soft-cap-amount after-soft-cap-duration)
[row
{:center "xs"
:style styles/margin-top-gutter-more}
(if (< total-contributed soft-cap-amount)
[:div
{:style styles/full-width}
[ui/linear-progress
{:mode "determinate"
:style styles/cap-progress
:color styles/theme-orange
:max soft-cap-amount
:value total-contributed}]
[:h3
{:style styles/full-width}
"Soft Cap " (js/parseInt total-contributed) "/" (or soft-cap-amount 0) " ETH"]
[:div
{:style (merge styles/full-width
styles/fade-white-text)}
"After soft cap is reached, the contribution period will be closed in " (t/in-hours (t/seconds after-soft-cap-duration))
" hours" [:br]
"In case of reaching " (or hard-cap-amount 0) " ETH hard cap, contribution period closes immediately"]]
[:div
{:style styles/full-width}
[ui/linear-progress
{:mode "determinate"
:style styles/cap-progress
:color styles/theme-orange
:max hard-cap-amount
:value total-contributed}]
[:h3
{:style styles/full-width}
"Hard Cap " (js/parseInt total-contributed) "/" (or hard-cap-amount 0) " ETH"]
[:div
{:style (merge styles/full-width
styles/fade-white-text)}
"After hard cap is reached, no more contributions will be accepted"]])])))))
(defn- external-link [body href]
[:a
{:href href
:target :_blank
:style {:color styles/theme-green}}
body])
(defn contribution-contribute-section []
(let [contribution-address (subscribe [:contribution-contract-address])
contribute-form (subscribe [:form.contribution/contribute])
can-use-form? (subscribe [:district0x/can-submit-into-blockchain?])
contrib-period-status (subscribe [:contribution/current-contrib-period-status])
current-contrib-period (subscribe [:contribution/contrib-period])
contrib-config (subscribe [:contribution/configuration])
confirmed-not-us-citizen? (subscribe [:confirmed-not-us-citizen?])
confirmed-terms? (subscribe [:confirmed-terms?])
confirmed-gas-price? (subscribe [:confirmed-gas-price?])
confirmed-compensation? (subscribe [:confirmed-compensation?])
confirmations-submitted? (subscribe [:confirmations-submitted?])
disallowed-country? (subscribe [:disallowed-country?])
]
(fn []
(let [{:keys [:contrib-period/stake :contrib-period/enabled?]} @current-contrib-period
{:keys [:data :loading?]} @contribute-form
{:keys [:contribution/amount]} data
{:keys [:contribution/stopped? :contribution/max-gas-price]} @contrib-config
error-text (cond
(not (u/non-neg-ether-value? amount)) "This is not valid Ether value"
(< (u/parse-float amount) constants/min-contrib-amount) (str "Minimum contribution amount is "
constants/min-contrib-amount
" ETH"))]
[row
{:center "xs"
:style styles/margin-top-gutter-more}
(if @disallowed-country?
[:div "We have detected that you are visiting this page from the United States or another unpermitted country. Please note: US citizens and residents are not permitted to participate in the district0x Contribution Period."]
(if @confirmations-submitted?
[:div
[:h2
{:style (merge styles/full-width
styles/margin-bottom-gutter-less)}
"How to Contribute"]
[:div
{:style (merge
{:color styles/theme-orange
:font-size "1em"}
styles/margin-bottom-gutter-less)}
[:b
"Important: Maximum allowed gas price is " (web3/from-wei max-gas-price :gwei) " Gwei "
"(" max-gas-price " wei)." [:br]
"Recommended gas limit is 200000" [:br]
(if stopped?
"Contribution was temporarily paused due to emergency"
({:contrib-period-status/not-started "Contribution period has not started yet"
:contrib-period-status/ended "Contribution period has been finished"}
@contrib-period-status))]]
[:div
{:style styles/full-width}
"You can send Ether directly to contribution smart contract at"]
[:h1
{:style (merge styles/full-width
styles/margin-top-gutter-less
{:color styles/theme-green
:font-family "filson-soft, sans-serif"})}
"district.eth" [:br]
[:span {:style {:font-size "0.7em"}} @contribution-address]]
[:div
{:style (merge styles/full-width
styles/margin-top-gutter-less)}
"or you can use following form by using " [external-link "MetaMask" "https://metamask.io/"] ", "
[external-link "Mist" "https://github.com/ethereum/mist"] ", or "
[external-link "Parity" "https://parity.io/"]]
[row
{:style styles/full-width
:middle "xs"
:center "xs"}
[ui/text-field
{:floating-label-fixed true
:floating-label-text "Amount in Ether"
:default-value amount
:style (merge {:margin-left styles/desktop-gutter-mini
:margin-right styles/desktop-gutter-mini}
styles/margin-bottom-gutter-less)
:error-text error-text
:error-style styles/text-left
:disabled (or (= :contrib-period-status/ended @contrib-period-status)
(not enabled?)
stopped?)
:on-change #(dispatch [:district0x.form/set-value :form.contribution/contribute :default :contribution/amount %2])}]
(if-not loading?
[ui/raised-button
{:primary true
:label "Send"
:disabled (or (not @can-use-form?)
(boolean error-text)
(= :contrib-period-status/ended @contrib-period-status)
(not enabled?)
stopped?)
:style {:margin-left styles/desktop-gutter-mini
:margin-right styles/desktop-gutter-mini
:margin-top 20}
:on-touch-tap #(dispatch [:contribution/contribute data])}]
[:div
{:style {:margin-top 20
:margin-left styles/desktop-gutter-mini
:margin-right styles/desktop-gutter-mini
:width 88}}
[ui/circular-progress
{:size 30
:thickness 2}]])]
[:div
{:style (merge styles/full-width)}
"For detailed instructions watch our "
[external-link "tutorials on Youtube" "https://www.youtube.com/channel/UCQq0INymkcGDYYXeFZgYk4g"]]]
[:div
{:style styles/full-width}
[:h2
{:style (merge styles/full-width
styles/margin-bottom-gutter)}
"Before You Contribute"]
[row
{:center "xs"
:style styles/full-width}
[:div
{:style styles/text-left}
[ui/checkbox
{:label "I confirm that I have read and agree to the Contribution Terms."
:checked @confirmed-terms?
:on-check #(dispatch [:set-confirmation :confirmed-terms? %2])}]
[ui/checkbox
{:label "I confirm that I am not a citizen or resident of the United States or other unpermitted country."
:checked @confirmed-not-us-citizen?
:on-check #(dispatch [:set-confirmation :confirmed-not-us-citizen? %2])}]
[ui/checkbox
{:label (r/as-element [:span "I understand "
[:b "the maximum gas price when contributing is 50 Gwei"]
" and any transaction sent with a higher gas price will be rejected."])
:checked @confirmed-gas-price?
:on-check #(dispatch [:set-confirmation :confirmed-gas-price? %2])}]
[ui/checkbox
{:label "I understand that it may take up to 7 days from the time the contribution period ends to receive DNT."
:checked @confirmed-compensation?
:on-check #(dispatch [:set-confirmation :confirmed-compensation? %2])}]]
[:div
{:style styles/full-width}
[ui/raised-button
{:primary true
:label "Continue"
:style styles/margin-top-gutter-less
:disabled (or (not @confirmed-terms?)
(not @confirmed-not-us-citizen?)
(not @confirmed-gas-price?)
(not @confirmed-compensation?))
:on-touch-tap #(dispatch [:set-confirmation :confirmations-submitted? true])}]]]]))
(when stake
[:div
[:div
{:style styles/distribution-note}
"Please note: " (u/format-eth stake) " DNT tokens will be divided and distributed amongst all
participants " [:b "after the contribution period ends"] ". Each participant will receive an allocation
proportional to the amount they contributed, relative to the total collected."]
[:div
{:style (merge styles/full-width
styles/margin-top-gutter)}
[:a {:href "https://district0x.io/docs/district0x-terms.pdf"
:target :_blank
:style styles/contrib-terms-link}
"Contribution Terms"]]])
[:small
{:style (merge styles/full-width
styles/fade-white-text
styles/margin-top-gutter
styles/margin-bottom-gutter-mini)}
"Copyright © 2017 district0x"]
[:div
{:style styles/full-width}
[:img {:src "./images/district0x-logo-title-white.svg"
:style {:height 15}}]]]))))
(defn contribution-panel []
[paper
[contribution-stats-tiles]
[contribution-soft-cap-progress]
[contribution-contribute-section]])
(defn logo []
[:a
{:href "https://district0x.io"}
[:img
{:style styles/logo
:src "./images/district0x-logo.svg"}]])
(defn main-panel []
(let [connection-error? (subscribe [:district0x/blockchain-connection-error?])
snackbar (subscribe [:district0x/snackbar])
contracts-not-found? (subscribe [:district0x/contracts-not-found?])
xs-width? (subscribe [:district0x/window-xs-width?])]
(fn []
[misc/main-panel
{:mui-theme styles/mui-theme}
[:div
{:style {:padding-bottom 20
:overflow :hidden
:position :relative
:min-height "100%"}}
[:img {:src "./images/green-blob2.svg"
:style styles/blob4}]
[:img {:src "./images/cyan-blob.svg"
:style styles/blob1}]
[:img {:src "./images/green-blob1.svg"
:style styles/blob2}]
[:img {:src "./images/green-blobs.svg"
:style styles/blob3}]
[ui/app-bar
{:show-menu-icon-button false
:style styles/app-bar
:title (r/as-element [logo])
:icon-element-right (r/as-element [app-bar-right-elements])}]
[:div {:style (merge styles/content-wrap
(when @xs-width?
(styles/padding-all styles/desktop-gutter-mini)))}
(if @contracts-not-found?
[contracts-not-found-page]
[center-layout
[contribution-panel]
[admin-panel]])]]])))
================================================
FILE: src/cljs/contribution/constants.cljs
================================================
(ns contribution.constants)
(def community-advisors
[["0x7e41aAa3623668e5D7D01B9b0340E65b515f3c83" 31000]
["0x841B0c3D98b7714c8b4a4c2312369E94AeC70f12" 1000]
["0xA7921Bb5389368C3B9C55605826Ed5c7656F0313" 1000]
["0xeE2E0E56e11faE260f3DE0D6767fc1e970FC69D3" 5000]
["0x00467579A3108e72d324771a66f2821f6bc6e61C" 1000]
["0x5C681875A0ef659D6d97Bc51c077783Db474dE47" 1000]
["0xc5f444774a79A772a7F4f20fFFe8c2dCB4115Ee1" 1000]
["0x0025a54871Dc1FBa33da0212453094f73Cf64066" 1000]
["0xC146a306CfC988a9fCB817dcaB3D1D0e0854CCD9" 1000]
["0xeE00F786C1799C82e7cb6292B1b96282b3C83ba2" 1000]
["0xB7f1498898d70685851B5331F64bF26215f00415" 1000]
["0xbd74F047cD88C3fCF52e47dE7Ae33c0fe40f33CD" 1000]
["0xd5FBD35C713178C4aC9d432528Bf8De747CbbdAF" 5000]
["0xb5A378c1Fd1F31f1077C89f448deE3488d81669D" 1000]
["0x16f4C2c13A6BceEdbd14e1A55E5A4c1Ac872Ee38" 1000]
["0xe5D93Dd474988B60b354339DA3a845D9cd35ec5F" 2000]
["0xd98b8BA6bEcf3694A8BDeBA0c9e9B1918E5C0CD8" 1000]
["0xBF9B1c552C1fDEeDcB6a05F5C3db563bBE10B4bb" 1000]
["0x5C71ded941d0377dd85F36EE23DDCa7BE7C8aC31" 150000]
["0x8C74EA7ad4e91390028fFefE46eD21D0DCd54A6A" 1000]
["0x762039f76394c51aa421B17832d3b9b6A39c9d3F" 1000]
["0x6e611765F7e2dB91e7876CBe683EFbe6393831a8" 1000]
["0x08D298D08bf9Ae07F000d3dFAFa3370169882d57" 1000]
["0x00ae0c1fd293038C2b24a715E6fAbAcDa6012b55" 1000]
["0x007ED64aC2fE49e1bcb932151e72dE0ca813ECF8" 1000]
["0x041DeDfeC783D8D6D8BD4f81Cb3675042151184D" 1000]
["0xb45489842B2F99e96f66a6eB486ae9c4F54A47c9" 1000]
["0x0fa38abec02bd4dbb87f189df50b674b9db0b468" 1000]
["0x3463DE8E9F42798C75492fE26273680F0fF0262C" 1000]
["0x46e886aE3DF8835F3aBb7310b667A91CdD7ddBaf" 1000]
["0x3EfEA862207f970a42e3DD2F31C9A29d3eF770Ac" 1000]
["0x5cb479DB92Ce3572383837c9775639dC373e4194" 1000]
["0xfF5166e66E389e07A50bc8232eB9Dc5a52Dc190b" 1000]
["0x4219791C5a6832c6475f51BAe55f49D59Fb4c3Bd" 1000]
["0x7c2be906222F1353D566c67A15Cc01a29c28DB84" 1000]
["0x66E8F875C6840aDEf012320Fb50C7e3264F321ec" 1000]
["0x244E9b38FC1c655de53A8ba5A4760F6E8001403b" 1000]
["0x660Ac3F4D700d7618Bb81aD68087eae967E996Ec" 1000]
["0x3Bb65357828Bd88457DA57cC7f144D004d3B036B" 1000]
["0x019EdcB493Bd91e2b25b70f26D5d9041Fd7EF946" 1000]
["0x70f421ca5D3263e82c155075a14EbCB7e5336643" 1000]
["0x1a716E83DbE858B34E7Fb1441fF9B8dbfa0c2BF4" 1000]
["0x0ddF6E4172fDd4D0389De04Bd440330FFC0eB96E" 1000]
["0x0061b82814878024452427f8087733aE46a5a61a" 20500]
["0x60819bb1DC2E213c4D9Ca008882b7180A93B9c66" 1000]
["0x48A473FEC94704B1a5Ceb7459d4E21Ce1f5580fC" 1000]
["0x52bB24A71aAb5f2DC01Aa1C8730aa27d9548Cd3a" 1000]
["0x0ae2e95ab1610cd35285bdb268d94b3f078e6b36" 1000]
["0x700694817BB4C7431ee19b51a002b062C6De7F80" 1000]
["0xc83585b0Bf139A392069eE22C14dd4D64D26079A" 3000]
["0x869e5B1bA479179f97D110D1D87f8E6dc7eB64Ae" 1000]
["0xbb36D3465D8afae08B08CB59eF389Cc9387eFf38" 1000]
["0x0e0CD189eC770A2814E78c9c9b022abdd5174723" 1000]
["0x6F9cb16EBcEB99cf88ac97c3E35698E0e3D48F47" 1000]
["0xE8Dde5cb737ad170Ed6349f958AF393368e7a36a" 1000]
["0x6a297d402907dC13D292000feD490099024C822a" 1000]
["0x2d3Dd55e97A9C8F07245eEb62846868990C258d6" 1000]
["0x177CB7154f67EBbA46a2d3553c47D90A6E28A2dA" 1000]
["0xae93A6CFb842495e38e7150c095B7c34D6485C82" 1000]
["0x9cbb422df9f16B925dD1fd48b82073Be4f740496" 1000]
["0x00eD1C405c08c87FDCd6C8A323180b82180A5730" 1000]
["0x906277eec52171EC7911f0ecfB54C74D9dE3F905" 1000]
["0x701d0ECB3BA780De7b2b36789aEC4493A426010a" 1000]
["0xc31Bcd3Fd846518B91669727de9cb8fccF07bCba" 1000]
["0x0B8C767a91DdbE99ABA14685d03B14D4265c1E5B" 1000]
["0x2D99B9B9Afc29dC2caB888C1E7928C7b131e4656" 1000]
["0x624DAeF5eA222Aad86d1a17EF72728169bDB360d" 61000]
["0x290Dbf7EB51324266F0668675a2a230d250b293C" 1000]
["0xa049C647eb5Ad083dD3Fb06d2a43Dbde30532072" 1000]
["0x2FB7206c0C2d2fa10BB9880f9Ff42177117713Cc" 1000]
["0x440c7EFe7fDD489c39B12ad0Fb8A8263c062ca72" 1000]
["0x82b3B3FfFD8680967305DeBf1816fe49b090670D" 1000]
["0xBffB814b73801Ff822427a3d8B902dbc8fFb5F93" 1000]
["0x69a7EA4c2e935c8c34B9C99d72Db71508F09AeBe" 1000]
["0xCb0ff21Aaf4CBC57B1B7EfBADbbd96D16ff50E57" 1000]
["0x7dD16CCa04E09C925D248AefEDa0c37cB76c7E16" 1000]
["0xc6Bffd211f37e24f9e870d4827C683B0a28B832e" 1000]
["0xd36eA428FF8796f94Aec58A063500023525A1201" 1000]
["0x03118e02cE007a0F0d1C9D806c2a7D5Ae2F26995" 3000]
["0x95A998c9af7b9199Ad9b117613be2Ad2b8eEd7e9" 1000]
["0xD9459cc85E78e0336aDb349EAbF257Dbaf9d5a2B" 1000]
["0xC49827499FD8dEebD14f6AC117022C99F99a2Ddc" 1000]
["0x51A125F89CBE0bFBFD62FeE8a750AAeC8fabC441" 10000]
["0xb6b81bbFE61a1Cf3F9a8E8514D5E0F7200CfCcA2" 1000]
["0x7dAfD53AEE8982aB1D767830c2fe50f62E3a98E6" 2000]
["0x7863FDcF1E54d0F442e663152F6ab2d8Bb98aDCF" 21000]
["0xc0B8705d2c92D7AfAD37cf7885b19eA60a9a1a71" 1000]
["0x2A8392859b3eF08659af44fBCABaD3BDE170f4C7" 1000]
["0x21Ac5f731b2AaFb6d7CcD20c1a70d5dFE320AEeb" 6000]
["0xf705CeB0f8b700d98978D5fC91F7705169e3e60e" 1000]
["0x665EaD9D831423e362D11BEaE3b9Dba380B8083A" 1000]
["0xDf40059dA4DdD74fEECE3f9c5Da76F8C3317F24f" 1000]
["0xa463F6edB92a2D7b9c90afc20a5Ce2116a945164" 1000]
["0x48ED6904Ce56349FBE802552e8E892c9500A22C3" 1000]
["0xb8a444F67d8d5e83425073dc05BbE3EBBf0b73Ad" 1000]
["0x84433D07A273a82626A3c7f4Fd6b7e44505Ec4F1" 1000]
["0xeaa40F6B29CE35d8F53f6bF9b2A7397E3D8475Af" 1000]
["0x5B17e67DAD94A65759B2e9555D8dA6A2B8db6BE7" 1000]
["0x611ec96B4dF9c8bbDB0258858C8451cAFedfDA34" 1000]
["0x7b486037E66eF9fB05aB44aaf905931Ba31539Aa" 3000]
["0x00a44164C421f4013d2E2E2e1CaeDA2A4763f386" 1000]
["0x863Be577Ebff3fc3094cd6D91c8eFa54d077c821" 1000]
["0x0f7ce02f8af040579eb7a93549bdcc965fa8eb7b" 1000]
["0x7617236eA6eBf579F36169369AF41fa0D8116506" 1000]
["0x007Dc7723F26b766c7bFE80764b004f5eDa03D78" 5000]
["0x35700c4a7bd65048f01d6675f09d15771c0facd5" 1000]
["0xf3B44AC5491E5349894D01532cDaeBa13311C041" 1000]
["0x79EbC54E8550D61a20794e0501E3D4fA5fCE76c7" 1000]
["0x55B39B67BB496B5E9F057Cde5E9F5173dCC66ADE" 1000]
["0x01E2f9Ba53b6Cb91e7f158090D24ebBcAdF0C564" 1000]
["0x564257bd12F17E3bcf0F3504FE0F5C8386254c39" 1000]
["0x3BBb5a4b05B8241ebB268c605541580270A2f3f5" 18000]
["0xe07449EF3ccEfAa15A29b66DE6634eB67229993e" 1000]
["0xB7Fb1BE386067BCb9Bc7481271B12f7Ce86ac82e" 1000]
["0x39f4662bf97200dbfa00ed05e3141c8959151cfa" 3000]
["0x747a8161c3880C67B17e8e0E52b960C15520BE10" 980000]
["0x792A57BE9b0E40E7bf2970Db901e5Ecd2DE30B7d" 1000]
["0xDd3b9BE91EA4D427e62c3fA3f2B27b5290d98F1e" 1000]
["0xa22D548B393736D0470584cCeE0cd59A90E15bBd" 1000]
["0x20083892b34A049bFAE1B2a6b070a71525e0b41A" 1000]
["0x1B5E3A4B53E1fFF879C718DE6afD45e4AFA6eF49" 1000]
["0xbe1b723aCd1F47c1AACE1014d24F6e489D3bc47B" 1000]
["0xa49b77305087d961612be78811c5d819928abef4" 1000]
["0xEd8B951463de0f10ff74CacFAc612526417a9D16" 200000]
["0xE5cbDF4d831fd46269c12ae2E4fB40606AF802aa" 1000]
["0x67936306c1490db7c491b0fe56bcf067ede1fd28" 1000]
["0x2322c22773C2d530dD5744A1Eea5a4be34c02dEA" 3000]
["0xc5465016B1c5abe438C62118bFf457f35CAA7881" 1000]
["0xA8E85dEe96F33Af3f5faae887dDf19260aDA2Ac7" 1000]
["0x98D5F2d180a811e1Ef17a2b3D501242d0a714eE7" 1000]
["0x0a94bcc0D0eC042CeD861d4D228bf8414B1d2956" 1000]
["0xE82522a784346926cf745605748d184Fae902727" 3000]
["0x00C4904FB17A6eCBfACb609273c89791aBA0a5cd" 3000]
["0x95c96042D5d3941DeB785EbabD313EB317717E45" 1000]
["0x26272474F4Bb38C04B1Bf1d9Fde567A578df7855" 2000]
["0xfF5Bd27500868847d996919aCEeD56a3C5E9D0e8" 1000]
["0x9CE315b846c211a05f9DE5578C74b875De470783" 1000]
["0xbCCc76522169bF83078aee30a509c32909D9AEa2" 1000]
["0x44C11Cf55b968eaE9F81044dcE6d6CBF15D36Bc8" 5000]
["0x00272A739927F587E2762D8BC77020B76BF73640" 5000]
["0xd5d28bbe1d2563addFaB1900F9dD7778cA515A9e" 5000]
["0xa5ed3807e915973d11947E26E742b6d6b8d05506" 20000]
["0x2C3F19eF4C6149cDdB84f8afbC4CA25e1FDB8926" 1000]
["0xd7fbb6b4D57e22fb34b7E30955791f7F06Ad92d2" 1000]
["0x1fA5Ec2f206Ea8fAf6c6D4919808339d3af3855D" 1000]
["0x560241585CBeDbEBDf105c53C291d7914110D495" 1000]
["0xe32c8561C14f5fCc6a4d4310cd866Ae48aAdd533" 1000]
["0xA5D9e7032d1A5656E2Ed80Bc6a716d57265141db" 2000]
["0x9cd6a59a40b7a88512999afc90220e5942e182ac" 1000]
["0xf16CFD73Fe21E1d2ffdC68C6348489AD917e8546" 3000]
["0x04b2986CEb58f87AE37267d36d666a1fC4894900" 10000]
["0xE73A1998cE936AceBEb7899D790a7a69c541b695" 10000]
["0x9e3bdfdf5b93832639ddfcb6f78b9fdc22788f5a" 1000]
["0xbb7730b90273D8ccd1Df142C712a864f4401CC78" 1000]
["0x00694C41975E95e435461192aBb86C56A3c2e66f" 1000]
["0x1E5E067B27ee101828364a6c542315a41A748cf8" 1000]
["0x28C2897122286A35738413E264942a781AF5c06A" 1000]
["0x0070Cfc95E4A24d8d43c5CF32390931439535227" 1000]
["0x7976B95F1C30725F25A2ee922c68a86a90Ff624C" 1000]
["0x1BD54855eF94cC9813B23464C6bC8afaa1a639e3" 1000]
["0x8E765AF6b5366A1c073600c1951C8998BF11ffa2" 1000]
["0x8FDa6640F52631253521D4605969cb92cA7BE94b" 1000]
["0xeB99C5E24011222F2e19a964939bb7B54fEcA22d" 3000]
["0xF34c0e5346cF57867A661e6B34ede6135d38bb85" 1000]
["0x7d97994332cd2d191845859b6d6F6D2270ECa45B" 1000]
["0xAff4f80ED19fA3b5856472362d77Dc87061aB932" 1000]
["0xf74c902f38e25a50464cccd24fdf94438dbd5d24" 1000]
["0xE71E66E9A1a53dBB9488C50b5bc08289afEF85f5" 1000]
["0x4eF6f3A56Ce63753EE82DD6e6654EaB912F7cECd" 5000]
["0xE5228908E0b5084af3dC95641F5b8055dd15edcd" 1000]
["0x8C0f64DdB364072ac54a5E5aC26F1ff1ACda38fc" 1000]
["0x2a57B99146fd06976C45F937604F0a19041938EA" 3000]
["0x839395e20bbB182fa440d08F850E6c7A8f6F0780" 50000]
["0x1DBA1131000664b884A1Ba238464159892252D3a" 50000]
["0x9082e0eAc4B7D13F6Db1259dfC8829859ED90329" 1000]
["0x25619749e040dec6a6832d60d228f867dd77c35d" 1000]
["0xeC92519007b823765664Beac13eFAF630C263316" 1000]
["0xF38852A25c1e3557D876e88E2FEE3522eFe03E96" 1000]
["0x6C22fa46Cb7FABd775bb0c4E13948e75Aa458a60" 1000]
["0x00049808dcce781C7FD603B9a2563c0932Ef6d29" 1000]
["0x0a417Def3B61404122c7580bfF82dc97E8a86D85" 150000]
["0x1Fd717A0AD0d3A163Fc7359c449A4a8490866Ce6" 2000]
["0x6cF4240145eFBF5a9Df664b6AaD55dc736DB037F" 1000]
["0xf8536CA7a25CBF70DF754fA310079aDa4c6114C2" 10000]
["0xf94eB69bcA6Eac9b97AFd1147C5B2Fa12e6D011B" 50000]
["0x0DE3145a2174608A7E389892b3Db1c9A3DE3DE1A" 1000]
["0x2fd4EC45ec04d33127E59CDfF2be4AC6d0B8C976" 2000]
["0x8911323De6b42df0bb9bD43d21e1D2E0C9236839" 5000]
["0x9C520c675BEB6eA07Aaf6F850a6Bc4Cd0724b015" 2000]
["0xdC1Fe37a00909ad34A827A377eBC184b897b8910" 1000]
["0xB7FeA0028b8EC4a0B651B060f58565EB6C57D507" 1000]
["0xB2839c0Fb42E66D8bAE27C2A0EAE5807e95e612A" 1000]
["0x4Ce0dadfCE28845aAF6812E5520f1F6c6406C72F" 1000]
["0x3eA10564417AdB679d149c2F4A3D118b0123e72D" 1000]
["0xf5a2cd399fb938b7fe2fce58b98b98b279a6ca63" 1000]
["0xeBe2c382b36145b8A4B37141CB141fd7d0B602A9" 1000]
["0x42C051538ae4d9523F910AB2Db41bF798f0DB344" 1000]
["0x441D034A49c17D079eFd70D477A180969b7fDa77" 1000]
["0xd4499ded424CA4d068D2f6B5eCf3d645D8e166ea" 1000]
["0x1141640AE469E5A9C99184AA4Cd55EE6C00fb4d2" 1000]
["0x3Ab76b9AF7da268A2dcAE0c2241fC37654d6DBea" 1000]
["0x4C1dD69120E1C82126677A6D30C2b61fec49cDd6" 1000]
["0x4161e7f10852b74713099Ca1a0Bd47fe341e5B52" 1000]
["0x2ee16239cfefc5e5f657e0aecc53b3643656dfa9" 1000]
["0xe9aaD3b8C643263935b45f74d0A5494ED5eF4AD7" 1000]
["0xe35c3F2211F9A0dC3883338Bc50A84DD16cb4cc2" 1000]
["0xeD523745Ac4D3b9313045C7d2238EdC2dFf50781" 1000]
["0xD9f3465E42B5F0eC627A156FB158b32Bc828CBB" 5000]
["0xaaE140fC38c11d085c14B38b0B9524DF6702bFFF" 1000]
["0x35ccE922b335aCe829A07F75Da01678a5931Eb3e" 1000]
["0x73a95DCa7522b9319a46f723Db44AF0c2F2cCe7c" 1000]
["0x1ad89A2B5537feF9799B64469E5f712F2d01a43E" 1000]
["0x6395DFf5ae32bEfaefA4CD6689E7Ed7CE5208069" 1000]
["0x442a1C75d6751F1E6b3C944C608336b41Bc9E696" 1000]
["0xDF90a56FeDE1dD8c2F89060dc8d649CAe1A026fC" 1000]
["0x24Cb28f325A9CE3C27D746e70Edeb9643f37c86E" 1000]
["0x0646F493FAC83c393A3b3B76669b52eDE6Ec5774" 1000]
["0x3215c214229e2310b0beb3a5b798849dd0882d28" 1000]
["0x812585402c94D4a4Fe0fa98FC05a4c2A404B05A7" 1000]
["0x1021F3AA2F1e8aBcf01c374305022b4B6e62135b" 1000]
["0xaaE140fC38c11d085c14B38b0B9524DF6702bFFF" 3000]
["0xA26776bC0d2079e550987F351969C727925FF6f9" 3000]
["0xa0298d6163B8f1d2594CB7C0dFa5359d4238f696" 1000]
["0x7AE7D714f5CF94A0DE58B178ecDbaaFE22482653" 1000]
["0xF19C090d039d08D85fA81f2b4095b9Fa66Aa8ea7" 1000]
["0x44010C025AE15838B92a43cA80BFAC1270888aAD" 1000]
["0x057b0175E2eD09CA783BC33C48cF31615B233692" 1000]
["0xF865a1226351A0C88e2497E057DDdBe5577D9852" 1000]
["0x185c742082316a46C0736c16F75332126F9c43d3" 1000]
["0x2aC079a959e3ca41B2cd5457b07930ABEB800943" 1000]
["0x0b738a03c82E6f06B723B6f4719581270E1477E6" 1000]
["0xE79E4a95dD61ca9E6ffD8821054a3745a229E33d" 25000]
["0x266DaF2B2c0F120A86F84f8190bdd0a264A62FE6" 1000]
["0xfC8b7d3405F68B07A84CC24caF79430f06618D8d" 1000]
["0xE72CE789BF6393771aa454e09Cd5be9715a83474" 1000]
["0x6E258688b739ebdB1F2Dcc4fbf7D96d0fa6Cacff" 36000]
["0x3ceBA254Ee10D70c1657F961D38423c65B0Ac9Fe" 3000]
["0x2a30Ac28acaAb47CC7B186a9cf6545FCD8ABC11F" 1000]
["0x15ff63d544ecB4a24969121b2F3239867D4F18E4" 1000]
["0xCC5479F7A6Cd4dCAA0F0fEd16E7952709ba1dC09" 1000]
["0x4b4BA59C1EaDaF4ce367445fDDd4218728A47b6a" 1000]
["0xe0c207F5c6Ab73C928a61F2b4B046cB86ce993dd" 1000]
["0x8e283225172CA64bfd44AC8D27CCf8728f5c2735" 1000]
["0x79b458A7abD79B5046a85Da12a1612e81678e7D9" 1000]
["0x4B00c6555ea388E9d881FF349256F0A4092F64e4" 1000]
["0x15EF0B50823C0c96EF201CB418E3785F6b8D7D59" 1000]
["0xfC8b7d3405F68B07A84CC24caF79430f06618D8d" 1000]
["0xA7bd17Ac3082a281FfAa2730f361E5c596224eaa" 1000]
["0x0a4231157671A451F1919d87f38bd0C307A0960F" 1000]
["0x8D32b2E44A3F9565c2Ed2FfDAFf7dB5D8212710a" 1000]
["0xc9D3879c3427aFd6E0cB83488Ff2000bDeb24Bc6" 1000]
["0x90cc6AD2f24209a127dD6247bf68acC0a453f2BF" 1000]
["0xe3517ae43529EF5243B1Ca137eAc764e66914871" 1000]
["0xc893c331A99Ec7A0CC186DFeD7F1F6E06a1A943F" 1000]
["0x88Bdb0aeC80e001738c101d111EE035F1eaC0D95" 2000]
["0x3592C46b40123Dd9ac242e37a94F4C8C082df439" 2000]
["0x6F0bECd0348CacAe43Ecd0f09805885675F51124" 2000]
["0xfa9150a1CFC22b18c93ef7A51fB2B1B8f48D1fdB" 1000]
["0xd046Cd27126d4f22C83Ba1d7C393d9b9A976f269" 1000]
["0xAe16d2f23e2389D3E60345AF20631Db806024C16" 1000]
["0x1aAa2834c52CFB38D035F328A0037E53A5fF7509" 1000]
["0xfC8b7d3405F68B07A84CC24caF79430f06618D8d" 1000]
["0xffb5d974cba1e8c3761427f017c9666c9f14c32b" 10000]
["0x06c1ca9861fc6DD78cF0Cf7381Ebd2B8254CaA1d" 1000]
["0xF7FC28C321fd17B8972BC2b2F53AaC7a22Ad228E" 1000]
["0x42c163Eff7D309425487CE50a9f4cB91DA19e4d1" 1000]
["0x019a5e8314d7273640cEf5675Cbfee834F4020C5" 1000]
["0x5108c73F481E8B6381AaA73325111EA6bFFfDa2f" 1000]
["0xDb25E5f07d8607823Fe76407046B0e469aCA164d" 1000]
["0xc8f1E7FF0E5066C8d8638575dBaD7CB261f19819" 1000]
["0x395f111e7dAE03BD7246b592be279ab344964dA5" 2000]
["0x4549DF8057aa166368aAAb2fe7af0AC2F1B6B01E" 1000]
["0x6765579e9750670d5bF03F4DAcCF21aFd691b0cF" 1000]
["0x8B0BCaf9f6c7b18810Eb412E08241659a20aDfd7" 1000]
["0xe675ECCf6C1D8Cfa2c3Ae29fa2AA325e2918d72e" 1000]
["0xd3AeA8b3db93F641fB0E2E51Fb41050e788412F7" 5000]
["0x24D39ecbDbBf850A13BD281827CFe6ada211b175" 1000]
["0xEd289a040f4e80FdD8D1065Eb9F4482b5bEe7A60" 1000]
["0xb93c1b96200f765D71f219A3Fa7CdCe0b7A1DA9b" 1000]
["0x9971DAA66B451338A2D6934D795549dbacD189E1" 1000]
["0x309DA4AD891E21b1527AF45a802fcAf97bd1e380" 1000]
["0xa91A30500A60258dC83F08bD7E29086F19E75E10" 1000]
["0x403629f0616767e437973323d2f0d3Ceb845f3a1" 1000]
["0xabb4639de78e88dabf47b8d659574dd660ffbb2c" 1000]
["0x3b630662cf15B0280A45bE85f1a175D5D8ED4939" 1000]
["0x106C21874eaA24d3bF34139281Ae5f1a82A101b6" 3000]
["0xA7Fd4bAfcF05DE525Dc7f235301FC7D15B1022A9" 1000]
["0xdd12d76573bffdd7e1e70359eb65e83910a0f35e" 1000]
["0x9c2238E76e267912EDB7817ce2C6E13468759110" 8000]
["0x583a22c4B14ae27ff4d25e9F1a2448ea9cce199a" 3000]
["0x2666Efbc740C0c57fd99B30cbe5132f934525637" 1000]
["0x252d3363191138D74bD017Bb81a9F1d64f5fcc0a" 1000]
["0x8635E9bBB8d628958787c227db6A3E070B9429dC" 1000]
["0x001A8821F547B1311dDbe86Bb59976ef66536fbB" 1000]
["0xb1b49Cd4Df741C883073c4f54f23921d6f2662C8" 1000]
["0x3eC827A91F8600c5e7D5a86Cdf9a0b913d84b6e6" 1000]
["0xc8e7E9B4335Ec38b1eF2c72274eBc530bb806B3c" 1000]
["0xACFe2fDdd3Ff10A5f9b0b2bbb581BdeCB8EA0287" 1000]
["0x44EC996aBF893285D567178149060B377BBC0151" 1000]
["0x0BF816Df8b8ad5b08490741B2b02b9C8b961CfE1" 1000]
["0xFd2262c369636E1c295C9aBA4CaD67316FBa74A2" 1000]
["0xc46D4a8737CedE0556425c8F346B48F75E0Dc741" 1000]
["0x00EA29cB2e2Ca58eC093BDC2C1400E91594609Cc" 50000]
["0xbBF8A5f7eC330ED877129e8195C72b521560158c" 1000]
["0xF04bA1E22Bf1d8819e373C2022861df56f60cB6c" 1000]
["0x8966FD4A3091C8c031F53Ad150a68D9235265EA7" 1000]
["0xf9e6341904be225154CdeC72B432AA3C67ad752B" 1000]
["0xd06CdbE139750F820B7E2298488B27E2e67f3B33" 1000]
["0x3EEBe3856B9a54276FEA2DF57934312F65f2E119" 1000]
["0x1297ac9bc3D892b647c9FE1f22E470560D711cA8" 1000]
["0x602889A6F2797451e30aFA98B508A404695a7e86" 1000]
["0x47f05aFF6ED5CADDb2332E9E48f64d62A5ad8Fe2" 1000]
["0x4D93604b66261116c9aac3E5d3e954BfEadA3a5D" 1000]
["0xa7ade07e80cf242dce085e545069b11c32fcc56e" 1000]
["0xd5ff18c05fb0aa587aadef87c8a8facc0d417b9a" 1000]
["0x6667273b97886f6583065c38e4732fc8b5e24ec5" 1000]
["0x6ed95B6fc786D426789Ff42b7d754fC26667bfAc" 1000]
["0x8bc1ab6fc6524335d723611b85a9f57ff6d3fcd3" 1000]
["0xa790266590062Aec36Fb3AAD7Bb4C0868C6AC992" 1000]
["0x30398e0f9e53475eefb5d60a52a048a2dc47709a" 1000]
["0xA9e2eFFBb7006c9E380FBda884EE316fC40F9cDD" 1000]
["0xA5F67CB29799087c817D1a7B76925e81b4be7f05" 1000]
["0x6308f9536c177059cFc4D78a1c8814a128Ce29D9" 1000]
["0x672f37e959Cc3606F4b95024feAe16135F2A93B7" 1000]
["0xcF876a3deF89b6e3DE37974190C843A83ACF090e" 1000]
["0xFFf94042354Cf1ffEEC622E4563774390c999dC8" 1000]
["0x2ba61dA3E9b2eB86879373EE337C1730990BacEA" 1000]
["0x156a58E7ed33baeb566c38caa200707E7daBfAe0" 1000]
["0x65ed0C1Ead5383988e556027Ac81F1acAD8d6A10" 1000]
["0xCA55BF46a8A01A283144F56C80c775b1f7786d9d" 1000]
["0x90e7aA0a9f37fa3930c1D33D57893E3372C84773" 1000]
["0x7e229c415ef56f8ea9ccca7291e88f0b3fa2bdcc" 1000]
["0xe4ef526473accbfc617451010beb5fbd68fe816d" 1000]
["0x5e51f674239f938110417a75e3f89d03d566b9ed" 1000]
["0x2e3313F1A506645c45E8d4ea27a25d8bA8d7eB9d" 1000]
["0x6957945e80280e63c8C51e54f2992e1E81DeCe84" 1000]
["0xF6284C62E081873dE747434EA38aD04559965DD9" 1000]
["0x072C075612aF238B2184CdcBc379B78eC048F918" 1000]
["0xdeE26DF7De15319697EcD1f81Ac374Ff0Bc06E09" 10000]
["0x8d2548cec0ac6807c0131e33360ad6e1332fe929" 1000]
["0x85c7716158d1050c918eb5859c5219fac0665eb7" 1000]
["0x509cfBd419e63264d4D92a39B414f2a8531dB0dc" 1000]
["0x430A499f2E0028C76618b3436BeD0952EB33bb6a" 3000]
["0x78CAc1584824dd9633d71f9EF41B56e6AA9927c0" 1000]
["0xB7BE0712d6ea427cE952539B52B0d10ea9a994b4" 1000]
["0xA85469B4c350D5177bA6657e138051a5C8171871" 1000]
["0x3aA2b7D989bD4145cF01c5f8e0710edCb9d7D0bB" 1000]
["0xaa8c09A4eD08B97F5886E067eA203656639ADfBc" 3000]
["0x23CC9a102eEe541d468B5F55d6dE1753fB245430" 1000]
["0x89628723da5101fcA70B4CA4dCB68A920ddC5A71" 1000]
["0x29367119856D241A401C79ED75571c323cF8373C" 1000]
["0xef44F365384ad909A3a885dc577d191b92292ba4" 1000]
["0x6e1323eF2554633375dC1D81696F9BA6fB18A2F5" 1000]
["0x8CD0C09B71a76298cE90459524883663C88D063F" 1000]
["0x924De4EFaC18ed4460C0b93d3bF726788E1a3F22" 1000]
["0xd9Cc2C57eb932E276B6663D55CdA63015d6801f9" 1000]
["0xf21749506CDC7C684b096bA172c99A8878a816FB" 5000]
["0xb8E1302A3390221A5375359E2Bb5f3f692725F46" 1000]
["0x5B62c6a32B64473C7Fb0bd94003990270E33eE9C" 1000]
["0x5210c0C80f14D07E415ad2d0A5A0AdDD16daB4c8" 1000]
["0x03b12981Ef4dF9bd810Ae12C53230BE9848AE5A5" 1000]
["0x7Ee084006b6Aea591DA21E26444915Fb57Ed647E" 1000]
["0xe6a024916a1936307Ea728A8F085d409ae5ecb10" 1000]
["0x1151D9EDA4d6415b57851F39894c0bC69134e86C" 1000]
["0x53e49353D37ad53CafFB4698CD9B7d831f55F707" 1000]
["0x9df1FCB2dcCA866bEdfb6514d3D5a1eBD522A544" 1000]
["0x1f05235F421c8CAe10CB593a1b4eAb2B17e4596a" 1000]
["0xcfd0055e61e4061052b77e51c8ce58e7a390bb90" 1000]
["0xF932b570f399fE46534613B16c9BB5744678a895" 1000]
["0xD38828D80aC4E5CF5F4A102494816945Ea37FB7B" 1000]
["0x9ceb60c1A364771a22e5707e137d168016c813DA" 1000]
["0xD6386Eff8a91ab3350E0A8009A9fF919484FB4AA" 1000]
["0x7E5d729704263f71D82fe2F8fC127526dddbC36C" 1000]
["0xeBcf2E9FAacB281c947A81759847139AE0Ad3992" 1000]
["0xa10Ce005fcdb49Ab04E05fdFE15539deef774fF3" 1000]
["0xc49d1085e06a93cD0F95dbD3C4e270Db7aB8f572" 1000]
["0xfB8FE962bE318fbB420ebA2D78E36836AE5Cef61" 1000]
["0x310Bc5f5746f7749eCdBBa01B4EAbC6F1A9a0E18" 1000]
["0x394B6a2a8ebc8Da4716F67a5F61ebe6f8d31C50A" 1000]
["0xb56E0bd6900311Db57e6D32e56F2bc995a1D1318" 1000]
["0xD4072DccceF9e050d29043e680f2574868C31021" 1000]
["0xdb4a0e45C50bF078f4e03d4C761F893184154977" 1000]
["0x814e400a8e169C736de1c620d7a84C43ef1b46F4" 1000]
["0x12040482Ab34ACbB440b17c64e7EB72253FD1401" 1000]
["0x910418Bc7839A456ba268E1D891d43AC6DD51AD6" 1000]
["0x83e5Df6fcC22e54Fcf9370FE4437c9cf251bCd54" 10000]
["0x65fac207ee655c873b5dcaae9a8d4140b15ec81e" 10000]
["0x7eB1e9267Ab19cefE7Dc068Be6c8f9dE42b0d85E" 12000]
["0x16C321252E56d1245151496D2F7FA4F4e8a3acdC" 1000]
["0x779a5D022ABf5A747194BB83cf2eF6B27cd1c48A" 1000]
["0xB4B9FAB079D452bd446F49C275417eF545F85BE7" 1000]
["0xD0d9754b02Cc1BA92217cC648B921e631f4C2e4f" 1000]
["0xF2f962ad05aEe8069B6e1e2AcE6E0C4b1414dF97" 1000]
["0xa8FF6589eE19df43D6580905Bf275DAb75Cf987B" 1000]
["0x1C609b9F8C77BF015dE1634De3Bd6158f091Bb4C" 1000]
["0x6C441eBA0ac23897B58c342f36a2D9a214593DdB" 1000]
["0x2F5C6A70c961EBc59DC943E4875af66318C4d75D" 1000]
["0x7D10aDDBb705e42cF68b07bb45C755E2Cff0ED1D" 1000]
["0xEd5830604989CcE0D9A3E97ECD84f3a66Df93bFe" 1000]
["0x335096bCAf8F2DFcB7506C01Ea00a5eec259a22b" 1000]
["0xCc6EAC5155D1eEaB6987b9efD791377Fd7C5539C" 1000]
["0xd17597f94ac4841ad8f24a2c222a3a056ad2116a" 25000]
["0xA43680F8E8694bedE9F2050920C2bfcb8687329c" 1000]
["0xbD6221808d98b601d343aC0aC7C0379F28399bde" 1000]
["0xE49eA037c47F4eb9b6e434B65902B759FDB08Bbe" 1000]
["0xcCE3F30cfEC3c5F090F0a8C94d8ca0e87be78879" 1000]
["0x87e6a0974B08Cd7156884912C5c63d30Ae2AFC1e" 1000]
["0xa8B4d876cDB3dD4f066FD830A21464daf8857c80" 1000]
["0x015E395AaA541574ea7b33A7803F67374C11c129" 1000]
["0x06905127EcB3f59c46a468489e5b262d7AfCc2e8" 50000]
["0xE4fbfe78a6F1Facb2D39141016a9A631F96b4F53" 1000]
["0xa2dEE84501a30b5847EcfEf8DB22a726EE911346" 1000]
["0x7ABCcb7afc349851d2f4E1D31A1f9DBd0e5F2F45" 1000]
["0xb305B0840c376CEB4176a0916b2593dE10abF8ee" 1000]
["0x904587Bb327E7a2CF439fA8606E4c9535FDC40Ae" 1000]
["0x92a5646e085051a8cC4a36a4CE9268AF223f0D4c" 1000]
["0xE6A9B3D0C232B5866ba0b90F0e3711AeF6E1D382" 1000]
["0xE6d80aC0aEb167DE108cfCf735e3FBD66DbB5802" 1000]
["0x00304C9D754Fa9B897Aa655D531AE125b7a12108" 1000]
["0xA92b2b995a6a09097a243dEbD79DcFC2B46848Ed" 1000]
["0xfD82A5b995ffF8FB85a01f4498994541a1d8eE60" 10000]
["0x19E580c6230b9194A7A0935ed4217CfFe8278adF" 1000]
["0x6E04454F2bb9D04F505C8b775E2e68cFc95F46D2" 5000]
["0x5C35A34977f83E049bd699e2481e21D116223B04" 1000]
["0x382bFcFf04b65E31CDD3f4310ad144C6905ED1cD" 1000]
["0x5457c5dd2c611c3E99902EAE1e89041bafF32a85" 1000]
["0xc008C29303b26f59453e9d79F37160909105250F" 1000]
["0x3785d73c25C4c08dC2c40fbA1CC845Fdc2210732" 1000]
["0x09ECb548371278A4fEE5E8e9B9bF1596F85d02c8" 1000]
["0xE3E3C3540FD428Aeb5828DFc2F6Fea7d20ebDF33" 1000]
["0x7Da722723897049fbe7d25cC1661102DE3fAf94E" 1000]
["0x0b48689A46F89b8149851021666CEa967902fc0C" 1000]
["0x6CF176CfcC5b82D5b14af25CF09bf3D6D37E1716" 1000]
["0xFfa6ADEC873c41f08d6D28d8f4eb978f968969f3" 1000]
["0x83e5Df6fcC22e54Fcf9370FE4437c9cf251bCd54" 1000]
["0xea9C95FB771De9e1E19aA25cA2E190aE96466CDD" 5000]
["0x41E53CD6Eb57CDb25ACE7eeBd212178cD358D48e" 1000]
["0xfb4abAe409A373d1994c62Dc0461a35b3c1B4089" 1000]
["0xC714d192D3904784137bDD316C423463aba0cEfc" 1000]
["0x2116Bc455dDf345539a738fdE43ABb63e6B0061C" 1000]
["0x88F78B27B0eaB9cB2f9108808070C7aa1E6A88b8" 5000]
["0xaf24Ba021B3e8D3a13b4691a2B0828dCd811545E" 50000]
["0xB7426E85Ca3eC67a009d30558062dda387cDb412" 50000]
["0x745E6bDDD3024E73daEc30d883A0A4e21D728cD9" 1000]
["0x59207cFeDa73D3B9Cb297d187446C7189D8e2bDC" 5000]
["0xd26bE7916836AECA8a7Cb41ef2f1e4299469f35D" 1000]
["0xFf628FCfAcd51760Dc145a8eC55fffd80749dbB9" 1000]
["0x7Da2eb91C6403d15e52Cba9539d4Bdec97c131dF" 1000]
["0x13a7D67c2228bA500375E4Ec78c9cd724B008491" 1000]
["0xC351Ff80e9F1Fb8ea0D3d6520DF678C6db9790C4" 1000]
["0xc7f148f442d5d76F2831A3053033E56F7A7573d3" 1000]
["0x7417030fD93C026b0735270f7a41B847044A637d" 1000]
["0x04a883fc7a3090d11B76601ae636F399fa747A51" 1000]
["0x0fA1f9E6B02d69Dd873bdC0dda9d8FfEa944F987" 1000]
["0xA6C1c8522B90138fc04eDFd3F8659210a710df81" 1000]
["0x9be64EC6D716699aBaE0661B6bd5602a3e38130A" 1000]
["0x37b9907d267Ad0D852A0490e77d37BE9A896c4A0" 1000]
["0x15E6a4EF615198d25a34DAFAe24446011400bedD" 1000]
["0x2A3bD9c6012920b7986da963C2244E3BEEdbaB1a" 1000]
["0xCF9b27Ff5A8a2B3E9048F833eA2E320B99Dd86BB" 1000]
["0xa59959D7DaaD25fd25781b7CEBcfd4303434e868" 1000]
["0x837259709B34FB0f1AEFA1644441057502998521" 1000]
["0x25864Cb83dccA71583E2958c52FCc5d9ADB6e4FC" 1000]
["0x8f6C1E30079535e45900Fd525fFA8BA1225F0EE8" 1000]
["0x13A33bB5321c1cb27C3F7011A9fFf1Dd5E660e74" 1000]
["0x9ca99bC90bc7C8F393848f4ff220e57202949654" 1000]
["0xa06d7BA83c7489716c9bA4429766D5Db8DeDC942" 1000]
["0x466Ad15Bfb27463BC2852f5fb925Cd2124495f06" 1000]
["0x08b55C4D3b0959D6F11fB3534970357765E16495" 1000]
["0xFE9f5d39BEcb99Ec713F46d9a55459A164ed95BE" 1000]
["0x45578b6c87d2B3981ab05dc149d360b92F4BeF3B" 1000]
["0x555084d6417304347357339300ca56016cc73290" 1000]
["0xFF8536eDDaD144A0005Cd6f34999A11a9A871DdF" 15000]
["0x2a84327E76f1C68FB6Ac9fCfc994cdc98fffc76F" 1000]
["0x0033e959d6e2574282B66071c4bA2fc01A338bA6" 15000]
["0xEB8664FCAc34e577D8A0C2FbF6d7AF68439FCC0C" 1000]
["0xDCb7f959d492Cd0E9441915dF1fEc58c7a6ECd93" 1000]
["0xf20D4dEe4E2E56768BA21Ed9edf6D95714F92993" 1000]
["0x54243AcE4f7B5f333090da5725082D857f914A18" 1000]
["0xfee48cEc41f071Bc462507d1E2fDa9B2fADB39C2" 1000]
["0x31fbdf54Ac00C6fE001aff1Bba93739289f066D3" 1000]
["0x0b4a9B08a05f5f0eeC936F3Bc8C259aCc1a24E8F" 1000]
["0x5B2E26c8d575F4E251142F2aD55510DAf2A89Ac7" 1000]
["0x9AA14a368D4bBdfA1Ae52BE735e90b34B251A120" 2000]
["0xc7fCEc0f33AB7a589c3E6D615d0aA19283D2ae6e" 1000]
["0xcea47EbD1e877fc651e72004e6C2F8bA8Bff3bC9" 1000]
["0x758f338534754eE7ea76a234332BA5EB695B2347" 1000]
["0xEdA350347cc954E219a70dc43a20426C98e4C0Be" 1000]
["0x826D4e2FcC0EeFC0De0DEaa868431d68f3004aC5" 1000]
["0x6d25A6343d3c9c0943F310aFBbD33D9Fa241E702" 1000]
["0xf25f1E156b5D329389eD7641A7a7012eAeb3172f" 1000]
["0x68583fe6A4c0E5De31EA6bdF352D8E5E897A6bB7" 1000]
["0x0801e3D533fA36BB5845994CB9b1869746d17DD7" 1000]
["0xd1108AD0B6B5e4b9017a545a6f808b2D0386d150" 1000]
["0xa75F95A04aa938B091e86cA5ca06A2d7d912173F" 1000]
["0x456D5C6c0322869e0e2beaad13819e7CA55D8006" 1000]
["0x1e1cCD5EC07e2D63e50ef2b183B66dB444C9f845" 5000]
["0xF8be4E6e786c4248b6dF08c5B766d786AE905B36" 1000]
["0xA28891F13275138e0b79569dD20D51e968827Cc1" 2000]
["0xCD41D02BDc943C3d8122C7fbCbb6487c642078A2" 10000]
["0x30b7908a77c07d1aE480d26D5039Ed01049AE1bf" 1000]
["0xDBfd04666F46Fc8CCadA187AD5Ecb736c0d09657" 1000]
["0x00ed6b3e01d2edafdefe598a7d962bbc7526629b" 5000]
["0x8A0bd511E47070cf9E358cb7754b9ceB56213c56" 1000]
["0xCF4173e010fC0C8dA4ba7443a7D5F52694Eb3928" 1000]
["0x7ec7b7FE8F255B3909313A37DdbFf407BF56F29e" 5000]
["0xDEd0a02807B8241703E2509A1Eaa2CC160bA53f1" 5000]
["0xae17ebd7f3bb7f74340647f68304fba0dcb7aa1d" 10000]
["0x0033e959d6e2574282B66071c4bA2fc01A338bA6" 5000]
["0x1B55887509d4d07965e20842cddaA1B1C4AD559c" 5000]
["0x01c68DE2A7A84BF0A58797C53aa91F08cF2A6cBf" 5000]
["0x6350632F0c38eF922EA2Eea20006779724eF0858" 7500]
["0x5cdc87001DD04b8A1257FdacfA67ae4d7F26B33a" 10000]
["0x0984274936F54ab6D34B6E4c1A8aAA92416e5cfe" 10000]
["0xc3B329f42CdB787c6600f7aE73632c037728c0a4" 5000]
["0x1F58868b6fA873739A07cB8D0412108Dc3B01733" 25000]
["0x3ac6cb2ccfd8c8aae3ba31d7ed44c20d241b16a4" 25000]
["0xa1C78ED146a8693A8cF3d29385BC54Cd3F145B4a" 10000]
["0x0d3A9470b55bb0131260b8d9941B37E6E35133aa" 5000]
["0x5ed1ac26ee940a42207955e119d283ecfe18a477" 25000]
["0x974c92f17621D11E60c724d193547b0533906191" 25000]
["0x4838eab6f43841e0d233db4cea47bd64f614f0c5" 25000]
["0xdA1F3a8603F8466Da8B4c95e8eFD8f87047467ac" 2000]
["0xEB6A307fCA343e103A177Eb67644D7Ed790Fbb33" 200000]
["0x8C3EaC201Ae1644eb6dA0F9318a2FF9C5F0c6D20" 500000]
["0x5A1495fAB6a150D9D0989B49e69bcD24F5fc243d" 1000]
["0xcdAA0072029E8c3e8C46c5Ed6c274cA6EA335a28" 20000]
["0x0a417Def3B61404122c7580bfF82dc97E8a86D85" 25000]
["0x000Fb8369677b3065dE5821a86Bc9551d5e5EAb9" 10000]
["0xc71a4798DBB8b85Db9e1b697B233F826B4F93dde" 10000]
["0x259fd04930947f4c12484d06e7251fcb38b57731" 1000]
["0x45f95DcC43424D500eB2c9C3eEd0Ad4159AceD5d" 10000]
["0x315A7B7160A12f036676a56B24e31B087387DA5d" 5000]
["0x4166ec103ea48ebc4d4538ac0f810f3472a8225d" 1000]
["0xd918219fd9bE2DE265438128988A0716C2BE1236" 1000]
["0x9d0A1C5741b6013A1681594d74bB5387b4e0d7C4" 1000]
["0xd4536721D929d66d645D6E6550aA06d8A82A95c6" 1000]
["0x18Fa802F9AA92CFfbd45f51e208a7D636612d65a" 1000]
["0x35854d221f0B2eDC4559e01e98f7De842C3e17d8" 1000]
["0xa386563bf026eEBe096fe26acc6e80Ba84D213a2" 1000]
["0x0EAC1BE5c2Bf16B9aE3DAd30F7815C466dB6Af8f" 1000]
["0xCd45dC40b5BD52284bF57a6C5c0ab3AA2f94c205" 1000]
["0xcA83fC54849e9a200b4401134B391E83b8D03ACF" 1000]
["0xA2537C2c3B8539744E2a1182C90A2c2d65E74ea8" 1000]
["0xa8c2c0007f4F50045241bF96aa1934B0ddA2528D" 1000]
["0xf6Ecc169e4E30d0d85e7696746ca87f0740C02BF" 1000]
["0x47dd3D9c9843f71eEDb4CdEA4ceB07E55B06adA0" 1000]
["0x86b717A8E106Ab0A84b6e1a3E47aBc60F643C81a" 1000]
["0x2Bc7e8EeC35CCB4644199Fd2C881eA8Da98a0cA9" 1000]
["0x101f0D604623783A9194e4a03e149c83bD94ED9c" 1000]
["0xfaE371BE58ce2199D48C9E2aa5f414dBE24b491d" 1000]
["0x424ce77Aff0D95615dA060bD3f8D570F774d633b" 1000]
["0xeAFEDde19F9c37e44f1Ec91487003Fdf895DdA3F" 1000]
["0x19Df053d56649E0A8ec11DD468cE280CC0F1dda0" 1000]
["0xE68eDa08389E8642E7b13Fc2e783f41150830a02" 1000]
["0x5858121D4Ccbc8095699a927d27CCc4460B5011E" 1000]
["0x9E10085270Ef7b0D2A9d2264803C295c545C81C1" 1000]
["0x097Eb69CD700C252Ae55AB123013b46BF68028f9" 1000]
["0xB00C946c53ab3b51F73C5DF7fcd10b39073e1790" 1000]
["0x004DccdCCd989fE30Ebb6ABc304cEBeCa438fa2b" 1000]
["0x09DB255Cd4e9927264391c87A6572338be33E08A" 1000]
["0xA25f2D38cB91F53136C25E553641E341D1cbd07f" 1000]
["0x7A33a5Bd15f3708dd0A8595b029D450fFcAa164f" 1000]
["0xef6Fa7B0B45F0273e5CBF740A150C4b1fB3Ba74A" 1000]
["0x8Fca7C9672c3C2db6FF538C858fEb66f6a90C6cc" 1000]
["0xB50d87cfF0D1708ecc0d6E5dc83862013624888A" 1000]
["0xb942eeE225766Db8180Fb3dd2CA00c3608BE0b8C" 1000]
["0x8ae03Fa94a53128AeCaAA3dfFB87FcA97797c1F0" 1000]
["0x949b82Dfc04558bC4D3CA033A1B194915a3A3bEE" 1000]
["0x126B62835b53360F226BE5c1fcD45B168afcc916" 1000]
["0xED2fd9b1bBb02a4cFa167942F771f7CFb522A0E6" 1000]
["0x05FFDec848E8Ca0AB751748A2cE3bf6bbAB91b24" 1000]
["0xcb584262393935eD3aCB5BeB81e2004a46A8482E" 1000]
["0x423CFB62c6ec7165C98964e2AB3865234F774756" 1000]
["0xA139E660CeF348d0e52bd2a5A280B663d8fd0379" 1000]
["0x678498BADBE31D20F718A303E51324a6D039E7AF" 1000]
["0x5bD4f1B3dd982DF217224B6c0967C700037a09be" 1000]
["0xcd13DE3339c03e97b01aDC779962D4d64e066d8e" 1000]
["0xA9501D1f52CA501ee432d62C6d89Cb77276FdfCe" 1000]
["0x58650c16afbD187686aB4D55B4AD9bf6191fefF2" 1000]
["0xfB9E00A0ADC832F82631a2D6f5467D802296249D" 1000]
["0xacD4e2556b363C1720184ebae82137211a773642" 1000]
["0x32bA4a7c41e164Cb6F9e6f406C2E35eC15db6Cd6" 1000]
["0x76e5fFFc26386E4D617eD6DF7Be9596f4007fCae" 1000]
["0x78508dEC3B3510B9f798693D6Df1b410CfC54280" 1000]
["0xcFE0909Dc95c2b22510Ea81f648Efb4b63c8021a" 1000]
["0xc1230cEe10dbbC41D9BB0D2df29603959c529419" 1000]
["0x6413CEF9F62Dc527CD8d3B971AfC2113d92D9b10" 1000]
["0x8FC70daAbDeFda552Ab7ddf089D2BfC6Cff17293" 1000]
["0x54F4e0063437be30Ba989Fe323c39FF7E41BB073" 1000]
["0x39de8D7AfA1Adb239fD1d59ACbb4CFdb87D3DCF6" 1000]
["0xE333aa1E1230CC722309d8d5f7F65fE8684c883d" 1000]
["0xAd4ecec26AeF498949e7eF64CC54372F1de52E51" 1000]
["0xFE88DD131d675874d8475ED6d3E3e92993f76d51" 1000]
["0x4a44dd1f701a90325513cad8a37d21f80dcc1da1" 1000]
["0x3C6b29F10f977c3314C7B528673B697839d0E19B" 1000]
["0x7E48aaCb783e1aA67A07CB8901067a2B03420c21" 1000]
["0x19b8eeBEC2E7427955D3E8916a1A608D9813A608" 1000]
["0xa4665c4524f09320b60f460c12DD943AacaD1b4b" 1000]
["0xBDA8106d4339eAec2396CDDEb2B93092CF97Ef01" 1000]
["0xA7d9c99De467C3558ADd28c057af8CeA9652395F" 1000]
["0x7f73803778ffBB312C3DBB5C48bBe0D1044D2273" 1000]
["0x4A70EE052822A4571642769dEed715D4bBABd3f8" 1000]
["0xF4509b36Dd69BCFbD45D79e56FA9B526aaa47788" 1000]
["0x3454319ba898F7ee3ab45409e1B415E8C16aCA3a" 1000]
["0xAEe48570A037Ec2aCf8E7Cf4710EE5a936561704" 1000]
["0x95f57d93effCfa494EB8d6F85d3f475107E0CE48" 1000]
["0xb1FBEb3273ad482AD276d4CdCaE560CE80e41394" 1000]
["0x989943F1DF0874e5735b6ec2fa4d221384CbB067" 1000]
["0xAeA4F88b8EEfe2C197b9AFb1FC053909549008b5" 1000]
["0xaB99F2AbA7d6CA4E61148a181036cfc84c680cb8" 1000]
["0x04DDA39c62312aE8b23bB4C36a703576C009327B" 1000]
["0x1d186680fea0c552ff4ed9F0bDCa1629e2EA1528" 1000]
["0x2B1000e66185905359B64DF9f0c8fCFd5929E457" 1000]
["0xa2781fbF8555cfAE3f98A213EE60AF17295aD156" 1000]
["0xBc55Cd5499DC8034f3e98a31D44421e4B16D6CBB" 1000]
["0x03439743652496291b17DDdBa5a93b9D8B9EB20D" 1000]
["0x739bf345F9CDAD9A4F6b827299dcAe222695F7d6" 1000]
["0xa3115D531b75BC72c796Af207192Fc960b615783" 1000]
["0xcD34DDEBaC48186Af7EA4a14F817831F5c74D56A" 1000]
["0x21Ec0929FEe996e938e3743B8d99dA877f80e748" 1000]
["0xbf489d7A7F4fb6cc75B231d69b3F6480064bf5A5" 1000]
["0x44E5030987cC08DdD4Ee77D76d1bA6424CAac5B4" 1000]
["0x2827d3f9C39bA0507710A0D813f8A1b2EC9d3C07" 1000]
["0x3C579133C724d42a557B3B8005C369d89a5d8BC7" 1000]
["0x96605f38873b4B00F3F6b1D122FBC82293672Bc2" 1000]
["0x70eb3bcecDC49615a805F8F0425E1AE2412De9a6" 1000]
["0xFf06A94E171fe7f29C4635B89756e59E66F9eBd8" 1000]
["0x766841734ef2a013374cb6E95458F498B9A617bC" 1000]
["0xF6825F6B83677ed6353c31B01BCe8363a2cCdCF3" 1000]
["0xC5EfE0F491aeb5D2E03143775f33135BE0CB9a31" 5000]
["0x5bB91b0b19E06ee8411431726F0c9661b1782070" 1000]
["0xcb1DDFcc09617aeb7E3bb4E58B2053B112324Ac1" 1000]
["0x7A3D3C991506432e09E05dB9cBeE8329e1067cAd" 1000]
["0xcaFe2a3a9a19F0E5D6A4A13620d6CB2a3a84cDF1" 5000]
["0xFBBc28653b2eF52Cde4a781de4Fb3b42FD308D55" 1000]
["0xd2E8bdCE6dc933eD4eEFcf7b069653F54823D3Fa" 1000]
["0x964B2B8083c40BcEb551BEe229ad84723F39dbA9" 1000]
["0x88E347aABCa0Ff031ef52937C6D56a7a6E4b0475" 1000]
["0x5e9ea9d04bff6e5416e5cd59d750293d4e186639" 5000]]
)
(def community-advisors-hashmap
{"0x9971DAA66B451338A2D6934D795549dbacD189E1" 1000,
"0xcCE3F30cfEC3c5F090F0a8C94d8ca0e87be78879" 1000,
"0xf94eB69bcA6Eac9b97AFd1147C5B2Fa12e6D011B" 50000,
"0x841B0c3D98b7714c8b4a4c2312369E94AeC70f12" 1000,
"0x1Fd717A0AD0d3A163Fc7359c449A4a8490866Ce6" 2000,
"0x266DaF2B2c0F120A86F84f8190bdd0a264A62FE6" 1000,
"0x01E2f9Ba53b6Cb91e7f158090D24ebBcAdF0C564" 1000,
"0xF4509b36Dd69BCFbD45D79e56FA9B526aaa47788" 1000,
"0x1297ac9bc3D892b647c9FE1f22E470560D711cA8" 1000,
"0x3215c214229e2310b0beb3a5b798849dd0882d28" 1000,
"0x7b486037E66eF9fB05aB44aaf905931Ba31539Aa" 3000,
"0xbd74F047cD88C3fCF52e47dE7Ae33c0fe40f33CD" 1000,
"0x48A473FEC94704B1a5Ceb7459d4E21Ce1f5580fC" 1000,
"0x00C4904FB17A6eCBfACb609273c89791aBA0a5cd" 3000,
"0xeE2E0E56e11faE260f3DE0D6767fc1e970FC69D3" 5000,
"0x156a58E7ed33baeb566c38caa200707E7daBfAe0" 1000,
"0x7D10aDDBb705e42cF68b07bb45C755E2Cff0ED1D" 1000,
"0xcd13DE3339c03e97b01aDC779962D4d64e066d8e" 1000,
"0x89628723da5101fcA70B4CA4dCB68A920ddC5A71" 1000,
"0x96605f38873b4B00F3F6b1D122FBC82293672Bc2" 1000,
"0xCF9b27Ff5A8a2B3E9048F833eA2E320B99Dd86BB" 1000,
"0x0d3A9470b55bb0131260b8d9941B37E6E35133aa" 5000,
"0x747a8161c3880C67B17e8e0E52b960C15520BE10" 980000,
"0xD9459cc85E78e0336aDb349EAbF257Dbaf9d5a2B" 1000,
"0xE5228908E0b5084af3dC95641F5b8055dd15edcd" 1000,
"0x66E8F875C6840aDEf012320Fb50C7e3264F321ec" 1000,
"0xeE00F786C1799C82e7cb6292B1b96282b3C83ba2" 1000,
"0x7A33a5Bd15f3708dd0A8595b029D450fFcAa164f" 1000,
"0xE79E4a95dD61ca9E6ffD8821054a3745a229E33d" 25000,
"0x0984274936F54ab6D34B6E4c1A8aAA92416e5cfe" 10000,
"0xFF8536eDDaD144A0005Cd6f34999A11a9A871DdF" 15000,
"0x6413CEF9F62Dc527CD8d3B971AfC2113d92D9b10" 1000,
"0x5457c5dd2c611c3E99902EAE1e89041bafF32a85" 1000,
"0x42C051538ae4d9523F910AB2Db41bF798f0DB344" 1000,
"0x964B2B8083c40BcEb551BEe229ad84723F39dbA9" 1000,
"0xFBBc28653b2eF52Cde4a781de4Fb3b42FD308D55" 1000,
"0xbBF8A5f7eC330ED877129e8195C72b521560158c" 1000,
"0x2C3F19eF4C6149cDdB84f8afbC4CA25e1FDB8926" 1000,
"0x244E9b38FC1c655de53A8ba5A4760F6E8001403b" 1000,
"0xc9D3879c3427aFd6E0cB83488Ff2000bDeb24Bc6" 1000,
"0x7AE7D714f5CF94A0DE58B178ecDbaaFE22482653" 1000,
"0xCd45dC40b5BD52284bF57a6C5c0ab3AA2f94c205" 1000,
"0x00eD1C405c08c87FDCd6C8A323180b82180A5730" 1000,
"0x5B2E26c8d575F4E251142F2aD55510DAf2A89Ac7" 1000,
"0x3EEBe3856B9a54276FEA2DF57934312F65f2E119" 1000,
"0x423CFB62c6ec7165C98964e2AB3865234F774756" 1000,
"0x54F4e0063437be30Ba989Fe323c39FF7E41BB073" 1000,
"0x177CB7154f67EBbA46a2d3553c47D90A6E28A2dA" 1000,
"0xa75F95A04aa938B091e86cA5ca06A2d7d912173F" 1000,
"0xd9Cc2C57eb932E276B6663D55CdA63015d6801f9" 1000,
"0x8C74EA7ad4e91390028fFefE46eD21D0DCd54A6A" 1000,
"0xA85469B4c350D5177bA6657e138051a5C8171871" 1000,
"0xd06CdbE139750F820B7E2298488B27E2e67f3B33" 1000,
"0xfaE371BE58ce2199D48C9E2aa5f414dBE24b491d" 1000,
"0x949b82Dfc04558bC4D3CA033A1B194915a3A3bEE" 1000,
"0xEB8664FCAc34e577D8A0C2FbF6d7AF68439FCC0C" 1000,
"0xC146a306CfC988a9fCB817dcaB3D1D0e0854CCD9" 1000,
"0x44C11Cf55b968eaE9F81044dcE6d6CBF15D36Bc8" 5000,
"0xe5D93Dd474988B60b354339DA3a845D9cd35ec5F" 2000,
"0xb1FBEb3273ad482AD276d4CdCaE560CE80e41394" 1000,
"0x25864Cb83dccA71583E2958c52FCc5d9ADB6e4FC" 1000,
"0xfa9150a1CFC22b18c93ef7A51fB2B1B8f48D1fdB" 1000,
"0x5108c73F481E8B6381AaA73325111EA6bFFfDa2f" 1000,
"0x44EC996aBF893285D567178149060B377BBC0151" 1000,
"0x7976B95F1C30725F25A2ee922c68a86a90Ff624C" 1000,
"0x442a1C75d6751F1E6b3C944C608336b41Bc9E696" 1000,
"0xb56E0bd6900311Db57e6D32e56F2bc995a1D1318" 1000,
"0x441D034A49c17D079eFd70D477A180969b7fDa77" 1000,
"0xa790266590062Aec36Fb3AAD7Bb4C0868C6AC992" 1000,
"0x9be64EC6D716699aBaE0661B6bd5602a3e38130A" 1000,
"0x39de8D7AfA1Adb239fD1d59ACbb4CFdb87D3DCF6" 1000,
"0xA7Fd4bAfcF05DE525Dc7f235301FC7D15B1022A9" 1000,
"0x7Da722723897049fbe7d25cC1661102DE3fAf94E" 1000,
"0xfb4abAe409A373d1994c62Dc0461a35b3c1B4089" 1000,
"0x2322c22773C2d530dD5744A1Eea5a4be34c02dEA" 3000,
"0xf20D4dEe4E2E56768BA21Ed9edf6D95714F92993" 1000,
"0x19Df053d56649E0A8ec11DD468cE280CC0F1dda0" 1000,
"0xaaE140fC38c11d085c14B38b0B9524DF6702bFFF" 3000,
"0x31fbdf54Ac00C6fE001aff1Bba93739289f066D3" 1000,
"0xF6284C62E081873dE747434EA38aD04559965DD9" 1000,
"0x00694C41975E95e435461192aBb86C56A3c2e66f" 1000,
"0x0801e3D533fA36BB5845994CB9b1869746d17DD7" 1000,
"0x0b738a03c82E6f06B723B6f4719581270E1477E6" 1000,
"0x403629f0616767e437973323d2f0d3Ceb845f3a1" 1000,
"0x0DE3145a2174608A7E389892b3Db1c9A3DE3DE1A" 1000,
"0x16C321252E56d1245151496D2F7FA4F4e8a3acdC" 1000,
"0x762039f76394c51aa421B17832d3b9b6A39c9d3F" 1000,
"0x701d0ECB3BA780De7b2b36789aEC4493A426010a" 1000,
"0x001A8821F547B1311dDbe86Bb59976ef66536fbB" 1000,
"0xc7fCEc0f33AB7a589c3E6D615d0aA19283D2ae6e" 1000,
"0xe9aaD3b8C643263935b45f74d0A5494ED5eF4AD7" 1000,
"0x78508dEC3B3510B9f798693D6Df1b410CfC54280" 1000,
"0x2a84327E76f1C68FB6Ac9fCfc994cdc98fffc76F" 1000,
"0x382bFcFf04b65E31CDD3f4310ad144C6905ED1cD" 1000,
"0xA5F67CB29799087c817D1a7B76925e81b4be7f05" 1000,
"0x2a30Ac28acaAb47CC7B186a9cf6545FCD8ABC11F" 1000,
"0xcb584262393935eD3aCB5BeB81e2004a46A8482E" 1000,
"0x6e611765F7e2dB91e7876CBe683EFbe6393831a8" 1000,
"0x1BD54855eF94cC9813B23464C6bC8afaa1a639e3" 1000,
"0x814e400a8e169C736de1c620d7a84C43ef1b46F4" 1000,
"0x45f95DcC43424D500eB2c9C3eEd0Ad4159AceD5d" 10000,
"0x6957945e80280e63c8C51e54f2992e1E81DeCe84" 1000,
"0x007Dc7723F26b766c7bFE80764b004f5eDa03D78" 5000,
"0x7Da2eb91C6403d15e52Cba9539d4Bdec97c131dF" 1000,
"0x00EA29cB2e2Ca58eC093BDC2C1400E91594609Cc" 50000,
"0xe0c207F5c6Ab73C928a61F2b4B046cB86ce993dd" 1000,
"0x904587Bb327E7a2CF439fA8606E4c9535FDC40Ae" 1000,
"0xeB99C5E24011222F2e19a964939bb7B54fEcA22d" 3000,
"0xa049C647eb5Ad083dD3Fb06d2a43Dbde30532072" 1000,
"0x660Ac3F4D700d7618Bb81aD68087eae967E996Ec" 1000,
"0xE5cbDF4d831fd46269c12ae2E4fB40606AF802aa" 1000,
"0x01c68DE2A7A84BF0A58797C53aa91F08cF2A6cBf" 5000,
"0xd3AeA8b3db93F641fB0E2E51Fb41050e788412F7" 5000,
"0xcb1DDFcc09617aeb7E3bb4E58B2053B112324Ac1" 1000,
"0x2A3bD9c6012920b7986da963C2244E3BEEdbaB1a" 1000,
"0x0033e959d6e2574282B66071c4bA2fc01A338bA6" 20000,
"0x6350632F0c38eF922EA2Eea20006779724eF0858" 7500,
"0x309DA4AD891E21b1527AF45a802fcAf97bd1e380" 1000,
"0xc5f444774a79A772a7F4f20fFFe8c2dCB4115Ee1" 1000,
"0x3454319ba898F7ee3ab45409e1B415E8C16aCA3a" 1000,
"0xb305B0840c376CEB4176a0916b2593dE10abF8ee" 1000,
"0xDEd0a02807B8241703E2509A1Eaa2CC160bA53f1" 5000,
"0xC5EfE0F491aeb5D2E03143775f33135BE0CB9a31" 5000,
"0x88F78B27B0eaB9cB2f9108808070C7aa1E6A88b8" 5000,
"0x83e5Df6fcC22e54Fcf9370FE4437c9cf251bCd54" 11000,
"0xbf489d7A7F4fb6cc75B231d69b3F6480064bf5A5" 1000,
"0x87e6a0974B08Cd7156884912C5c63d30Ae2AFC1e" 1000,
"0xAEe48570A037Ec2aCf8E7Cf4710EE5a936561704" 1000,
"0x335096bCAf8F2DFcB7506C01Ea00a5eec259a22b" 1000,
"0xe07449EF3ccEfAa15A29b66DE6634eB67229993e" 1000,
"0xdeE26DF7De15319697EcD1f81Ac374Ff0Bc06E09" 10000,
"0x126B62835b53360F226BE5c1fcD45B168afcc916" 1000,
"0xe35c3F2211F9A0dC3883338Bc50A84DD16cb4cc2" 1000,
"0x430A499f2E0028C76618b3436BeD0952EB33bb6a" 3000,
"0x60819bb1DC2E213c4D9Ca008882b7180A93B9c66" 1000,
"0xc1230cEe10dbbC41D9BB0D2df29603959c529419" 1000,
"0x48ED6904Ce56349FBE802552e8E892c9500A22C3" 1000,
"0xd7fbb6b4D57e22fb34b7E30955791f7F06Ad92d2" 1000,
"0xa8FF6589eE19df43D6580905Bf275DAb75Cf987B" 1000,
"0x259fd04930947f4c12484d06e7251fcb38b57731" 1000,
"0xB7Fb1BE386067BCb9Bc7481271B12f7Ce86ac82e" 1000,
"0x1DBA1131000664b884A1Ba238464159892252D3a" 50000,
"0x097Eb69CD700C252Ae55AB123013b46BF68028f9" 1000,
"0xd918219fd9bE2DE265438128988A0716C2BE1236" 1000,
"0x5cb479DB92Ce3572383837c9775639dC373e4194" 1000,
"0xef44F365384ad909A3a885dc577d191b92292ba4" 1000,
"0x678498BADBE31D20F718A303E51324a6D039E7AF" 1000,
"0xCA55BF46a8A01A283144F56C80c775b1f7786d9d" 1000,
"0x08D298D08bf9Ae07F000d3dFAFa3370169882d57" 1000,
"0x9082e0eAc4B7D13F6Db1259dfC8829859ED90329" 1000,
"0x95A998c9af7b9199Ad9b117613be2Ad2b8eEd7e9" 1000,
"0x8FDa6640F52631253521D4605969cb92cA7BE94b" 1000,
"0xD0d9754b02Cc1BA92217cC648B921e631f4C2e4f" 1000,
"0xdA1F3a8603F8466Da8B4c95e8eFD8f87047467ac" 2000,
"0xA28891F13275138e0b79569dD20D51e968827Cc1" 2000,
"0x2d3Dd55e97A9C8F07245eEb62846868990C258d6" 1000,
"0x95f57d93effCfa494EB8d6F85d3f475107E0CE48" 1000,
"0x9ceb60c1A364771a22e5707e137d168016c813DA" 1000,
"0xa8c2c0007f4F50045241bF96aa1934B0ddA2528D" 1000,
"0xBDA8106d4339eAec2396CDDEb2B93092CF97Ef01" 1000,
"0x989943F1DF0874e5735b6ec2fa4d221384CbB067" 1000,
"0xa7ade07e80cf242dce085e545069b11c32fcc56e" 1000,
"0xFfa6ADEC873c41f08d6D28d8f4eb978f968969f3" 1000,
"0xbb36D3465D8afae08B08CB59eF389Cc9387eFf38" 1000,
"0xacD4e2556b363C1720184ebae82137211a773642" 1000,
"0x7417030fD93C026b0735270f7a41B847044A637d" 1000,
"0x82b3B3FfFD8680967305DeBf1816fe49b090670D" 1000,
"0x839395e20bbB182fa440d08F850E6c7A8f6F0780" 50000,
"0xB4B9FAB079D452bd446F49C275417eF545F85BE7" 1000,
"0xA6C1c8522B90138fc04eDFd3F8659210a710df81" 1000,
"0xeBe2c382b36145b8A4B37141CB141fd7d0B602A9" 1000,
"0xFE9f5d39BEcb99Ec713F46d9a55459A164ed95BE" 1000,
"0x3eC827A91F8600c5e7D5a86Cdf9a0b913d84b6e6" 1000,
"0xae93A6CFb842495e38e7150c095B7c34D6485C82" 1000,
"0xfB8FE962bE318fbB420ebA2D78E36836AE5Cef61" 1000,
"0x92a5646e085051a8cC4a36a4CE9268AF223f0D4c" 1000,
"0x32bA4a7c41e164Cb6F9e6f406C2E35eC15db6Cd6" 1000,
"0x837259709B34FB0f1AEFA1644441057502998521" 1000,
"0xb93c1b96200f765D71f219A3Fa7CdCe0b7A1DA9b" 1000,
"0x007ED64aC2fE49e1bcb932151e72dE0ca813ECF8" 1000,
"0xE3E3C3540FD428Aeb5828DFc2F6Fea7d20ebDF33" 1000,
"0x5210c0C80f14D07E415ad2d0A5A0AdDD16daB4c8" 1000,
"0x3C579133C724d42a557B3B8005C369d89a5d8BC7" 1000,
"0x6C22fa46Cb7FABd775bb0c4E13948e75Aa458a60" 1000,
"0xCc6EAC5155D1eEaB6987b9efD791377Fd7C5539C" 1000,
"0xA5D9e7032d1A5656E2Ed80Bc6a716d57265141db" 2000,
"0x101f0D604623783A9194e4a03e149c83bD94ED9c" 1000,
"0x1B55887509d4d07965e20842cddaA1B1C4AD559c" 5000,
"0x04a883fc7a3090d11B76601ae636F399fa747A51" 1000,
"0x766841734ef2a013374cb6E95458F498B9A617bC" 1000,
"0x35854d221f0B2eDC4559e01e98f7De842C3e17d8" 1000,
"0x8bc1ab6fc6524335d723611b85a9f57ff6d3fcd3" 1000,
"0xAeA4F88b8EEfe2C197b9AFb1FC053909549008b5" 1000,
"0x3ceBA254Ee10D70c1657F961D38423c65B0Ac9Fe" 3000,
"0x4B00c6555ea388E9d881FF349256F0A4092F64e4" 1000,
"0xfF5Bd27500868847d996919aCEeD56a3C5E9D0e8" 1000,
"0xc46D4a8737CedE0556425c8F346B48F75E0Dc741" 1000,
"0xA7d9c99De467C3558ADd28c057af8CeA9652395F" 1000,
"0xf5a2cd399fb938b7fe2fce58b98b98b279a6ca63" 1000,
"0xd36eA428FF8796f94Aec58A063500023525A1201" 1000,
"0x315A7B7160A12f036676a56B24e31B087387DA5d" 5000,
"0x68583fe6A4c0E5De31EA6bdF352D8E5E897A6bB7" 1000,
"0xE8Dde5cb737ad170Ed6349f958AF393368e7a36a" 1000,
"0xAd4ecec26AeF498949e7eF64CC54372F1de52E51" 1000,
"0x8C0f64DdB364072ac54a5E5aC26F1ff1ACda38fc" 1000,
"0xe3517ae43529EF5243B1Ca137eAc764e66914871" 1000,
"0x019EdcB493Bd91e2b25b70f26D5d9041Fd7EF946" 1000,
"0x4Ce0dadfCE28845aAF6812E5520f1F6c6406C72F" 1000,
"0xA25f2D38cB91F53136C25E553641E341D1cbd07f" 1000,
"0xf6Ecc169e4E30d0d85e7696746ca87f0740C02BF" 1000,
"0xFf06A94E171fe7f29C4635B89756e59E66F9eBd8" 1000,
"0xE333aa1E1230CC722309d8d5f7F65fE8684c883d" 1000,
"0xCF4173e010fC0C8dA4ba7443a7D5F52694Eb3928" 1000,
"0x0f7ce02f8af040579eb7a93549bdcc965fa8eb7b" 1000,
"0x555084d6417304347357339300ca56016cc73290" 1000,
"0xfF5166e66E389e07A50bc8232eB9Dc5a52Dc190b" 1000,
"0x7f73803778ffBB312C3DBB5C48bBe0D1044D2273" 1000,
"0x04b2986CEb58f87AE37267d36d666a1fC4894900" 10000,
"0x4C1dD69120E1C82126677A6D30C2b61fec49cDd6" 1000,
"0xCD41D02BDc943C3d8122C7fbCbb6487c642078A2" 10000,
"0x2e3313F1A506645c45E8d4ea27a25d8bA8d7eB9d" 1000,
"0xf9e6341904be225154CdeC72B432AA3C67ad752B" 1000,
"0x0ae2e95ab1610cd35285bdb268d94b3f078e6b36" 1000,
"0x84433D07A273a82626A3c7f4Fd6b7e44505Ec4F1" 1000,
"0x45578b6c87d2B3981ab05dc149d360b92F4BeF3B" 1000,
"0x1f05235F421c8CAe10CB593a1b4eAb2B17e4596a" 1000,
"0xE82522a784346926cf745605748d184Fae902727" 3000,
"0x5bD4f1B3dd982DF217224B6c0967C700037a09be" 1000,
"0xDCb7f959d492Cd0E9441915dF1fEc58c7a6ECd93" 1000,
"0x2666Efbc740C0c57fd99B30cbe5132f934525637" 1000,
"0x6667273b97886f6583065c38e4732fc8b5e24ec5" 1000,
"0xcD34DDEBaC48186Af7EA4a14F817831F5c74D56A" 1000,
"0x974c92f17621D11E60c724d193547b0533906191" 25000,
"0xe6a024916a1936307Ea728A8F085d409ae5ecb10" 1000,
"0x7863FDcF1E54d0F442e663152F6ab2d8Bb98aDCF" 21000,
"0x7617236eA6eBf579F36169369AF41fa0D8116506" 1000,
"0xdd12d76573bffdd7e1e70359eb65e83910a0f35e" 1000,
"0xef6Fa7B0B45F0273e5CBF740A150C4b1fB3Ba74A" 1000,
"0x9AA14a368D4bBdfA1Ae52BE735e90b34B251A120" 2000,
"0x0EAC1BE5c2Bf16B9aE3DAd30F7815C466dB6Af8f" 1000,
"0x7E48aaCb783e1aA67A07CB8901067a2B03420c21" 1000,
"0x8Fca7C9672c3C2db6FF538C858fEb66f6a90C6cc" 1000,
"0x000Fb8369677b3065dE5821a86Bc9551d5e5EAb9" 10000,
"0x35ccE922b335aCe829A07F75Da01678a5931Eb3e" 1000,
"0x5B62c6a32B64473C7Fb0bd94003990270E33eE9C" 1000,
"0x560241585CBeDbEBDf105c53C291d7914110D495" 1000,
"0xDf40059dA4DdD74fEECE3f9c5Da76F8C3317F24f" 1000,
"0x395f111e7dAE03BD7246b592be279ab344964dA5" 2000,
"0x4b4BA59C1EaDaF4ce367445fDDd4218728A47b6a" 1000,
"0x3C6b29F10f977c3314C7B528673B697839d0E19B" 1000,
"0x252d3363191138D74bD017Bb81a9F1d64f5fcc0a" 1000,
"0x0070Cfc95E4A24d8d43c5CF32390931439535227" 1000,
"0xb942eeE225766Db8180Fb3dd2CA00c3608BE0b8C" 1000,
"0xF04bA1E22Bf1d8819e373C2022861df56f60cB6c" 1000,
"0xbe1b723aCd1F47c1AACE1014d24F6e489D3bc47B" 1000,
"0x44010C025AE15838B92a43cA80BFAC1270888aAD" 1000,
"0x0fA1f9E6B02d69Dd873bdC0dda9d8FfEa944F987" 1000,
"0x466Ad15Bfb27463BC2852f5fb925Cd2124495f06" 1000,
"0xe32c8561C14f5fCc6a4d4310cd866Ae48aAdd533" 1000,
"0x20083892b34A049bFAE1B2a6b070a71525e0b41A" 1000,
"0xd5FBD35C713178C4aC9d432528Bf8De747CbbdAF" 5000,
"0x47f05aFF6ED5CADDb2332E9E48f64d62A5ad8Fe2" 1000,
"0x9E10085270Ef7b0D2A9d2264803C295c545C81C1" 1000,
"0x70eb3bcecDC49615a805F8F0425E1AE2412De9a6" 1000,
"0x0B8C767a91DdbE99ABA14685d03B14D4265c1E5B" 1000,
"0x9d0A1C5741b6013A1681594d74bB5387b4e0d7C4" 1000,
"0x440c7EFe7fDD489c39B12ad0Fb8A8263c062ca72" 1000,
"0xc008C29303b26f59453e9d79F37160909105250F" 1000,
"0xF932b570f399fE46534613B16c9BB5744678a895" 1000,
"0x1C609b9F8C77BF015dE1634De3Bd6158f091Bb4C" 1000,
"0x69a7EA4c2e935c8c34B9C99d72Db71508F09AeBe" 1000,
"0x1aAa2834c52CFB38D035F328A0037E53A5fF7509" 1000,
"0xF7FC28C321fd17B8972BC2b2F53AaC7a22Ad228E" 1000,
"0x826D4e2FcC0EeFC0De0DEaa868431d68f3004aC5" 1000,
"0x5858121D4Ccbc8095699a927d27CCc4460B5011E" 1000,
"0x6cF4240145eFBF5a9Df664b6AaD55dc736DB037F" 1000,
"0x00467579A3108e72d324771a66f2821f6bc6e61C" 1000,
"0x5C681875A0ef659D6d97Bc51c077783Db474dE47" 1000,
"0xcaFe2a3a9a19F0E5D6A4A13620d6CB2a3a84cDF1" 5000,
"0x51A125F89CBE0bFBFD62FeE8a750AAeC8fabC441" 10000,
"0xa2781fbF8555cfAE3f98A213EE60AF17295aD156" 1000,
"0xa49b77305087d961612be78811c5d819928abef4" 1000,
"0xcFE0909Dc95c2b22510Ea81f648Efb4b63c8021a" 1000,
"0x1fA5Ec2f206Ea8fAf6c6D4919808339d3af3855D" 1000,
"0x906277eec52171EC7911f0ecfB54C74D9dE3F905" 1000,
"0xc3B329f42CdB787c6600f7aE73632c037728c0a4" 5000,
"0x06c1ca9861fc6DD78cF0Cf7381Ebd2B8254CaA1d" 1000,
"0xE4fbfe78a6F1Facb2D39141016a9A631F96b4F53" 1000,
"0xEB6A307fCA343e103A177Eb67644D7Ed790Fbb33" 200000,
"0x00272A739927F587E2762D8BC77020B76BF73640" 5000,
"0x672f37e959Cc3606F4b95024feAe16135F2A93B7" 1000,
"0x5C71ded941d0377dd85F36EE23DDCa7BE7C8aC31" 150000,
"0xF19C090d039d08D85fA81f2b4095b9Fa66Aa8ea7" 1000,
"0x21Ec0929FEe996e938e3743B8d99dA877f80e748" 1000,
"0xA2537C2c3B8539744E2a1182C90A2c2d65E74ea8" 1000,
"0x0BF816Df8b8ad5b08490741B2b02b9C8b961CfE1" 1000,
"0x7c2be906222F1353D566c67A15Cc01a29c28DB84" 1000,
"0xE6d80aC0aEb167DE108cfCf735e3FBD66DbB5802" 1000,
"0x00a44164C421f4013d2E2E2e1CaeDA2A4763f386" 1000,
"0x13a7D67c2228bA500375E4Ec78c9cd724B008491" 1000,
"0x739bf345F9CDAD9A4F6b827299dcAe222695F7d6" 1000,
"0xc5465016B1c5abe438C62118bFf457f35CAA7881" 1000,
"0x79EbC54E8550D61a20794e0501E3D4fA5fCE76c7" 1000,
"0xD6386Eff8a91ab3350E0A8009A9fF919484FB4AA" 1000,
"0x3aA2b7D989bD4145cF01c5f8e0710edCb9d7D0bB" 1000,
"0xA139E660CeF348d0e52bd2a5A280B663d8fd0379" 1000,
"0xB50d87cfF0D1708ecc0d6E5dc83862013624888A" 1000,
"0x46e886aE3DF8835F3aBb7310b667A91CdD7ddBaf" 1000,
"0x1a716E83DbE858B34E7Fb1441fF9B8dbfa0c2BF4" 1000,
"0x4166ec103ea48ebc4d4538ac0f810f3472a8225d" 1000,
"0xC714d192D3904784137bDD316C423463aba0cEfc" 1000,
"0x2F5C6A70c961EBc59DC943E4875af66318C4d75D" 1000,
"0xc6Bffd211f37e24f9e870d4827C683B0a28B832e" 1000,
"0x79b458A7abD79B5046a85Da12a1612e81678e7D9" 1000,
"0x9e3bdfdf5b93832639ddfcb6f78b9fdc22788f5a" 1000,
"0x1141640AE469E5A9C99184AA4Cd55EE6C00fb4d2" 1000,
"0x1E5E067B27ee101828364a6c542315a41A748cf8" 1000,
"0x8D32b2E44A3F9565c2Ed2FfDAFf7dB5D8212710a" 1000,
"0xF865a1226351A0C88e2497E057DDdBe5577D9852" 1000,
"0xFf628FCfAcd51760Dc145a8eC55fffd80749dbB9" 1000,
"0x602889A6F2797451e30aFA98B508A404695a7e86" 1000,
"0x44E5030987cC08DdD4Ee77D76d1bA6424CAac5B4" 1000,
"0x1151D9EDA4d6415b57851F39894c0bC69134e86C" 1000,
"0x6d25A6343d3c9c0943F310aFBbD33D9Fa241E702" 1000,
"0xd1108AD0B6B5e4b9017a545a6f808b2D0386d150" 1000,
"0x509cfBd419e63264d4D92a39B414f2a8531dB0dc" 1000,
"0xEd8B951463de0f10ff74CacFAc612526417a9D16" 200000,
"0x29367119856D241A401C79ED75571c323cF8373C" 1000,
"0x6395DFf5ae32bEfaefA4CD6689E7Ed7CE5208069" 1000,
"0x26272474F4Bb38C04B1Bf1d9Fde567A578df7855" 2000,
"0xdb4a0e45C50bF078f4e03d4C761F893184154977" 1000,
"0x2B1000e66185905359B64DF9f0c8fCFd5929E457" 1000,
"0x7d97994332cd2d191845859b6d6F6D2270ECa45B" 1000,
"0xb8a444F67d8d5e83425073dc05BbE3EBBf0b73Ad" 1000,
"0xE73A1998cE936AceBEb7899D790a7a69c541b695" 10000,
"0xC351Ff80e9F1Fb8ea0D3d6520DF678C6db9790C4" 1000,
"0x779a5D022ABf5A747194BB83cf2eF6B27cd1c48A" 1000,
"0x35700c4a7bd65048f01d6675f09d15771c0facd5" 1000,
"0x8A0bd511E47070cf9E358cb7754b9ceB56213c56" 1000,
"0x3EfEA862207f970a42e3DD2F31C9A29d3eF770Ac" 1000,
"0xe675ECCf6C1D8Cfa2c3Ae29fa2AA325e2918d72e" 1000,
"0x0b4a9B08a05f5f0eeC936F3Bc8C259aCc1a24E8F" 1000,
"0xEdA350347cc954E219a70dc43a20426C98e4C0Be" 1000,
"0x9CE315b846c211a05f9DE5578C74b875De470783" 1000,
"0x16f4C2c13A6BceEdbd14e1A55E5A4c1Ac872Ee38" 1000,
"0x19b8eeBEC2E7427955D3E8916a1A608D9813A608" 1000,
"0x7e41aAa3623668e5D7D01B9b0340E65b515f3c83" 31000,
"0xfD82A5b995ffF8FB85a01f4498994541a1d8eE60" 10000,
"0x2FB7206c0C2d2fa10BB9880f9Ff42177117713Cc" 1000,
"0x5cdc87001DD04b8A1257FdacfA67ae4d7F26B33a" 10000,
"0x8FC70daAbDeFda552Ab7ddf089D2BfC6Cff17293" 1000,
"0x4219791C5a6832c6475f51BAe55f49D59Fb4c3Bd" 1000,
"0xb8E1302A3390221A5375359E2Bb5f3f692725F46" 1000,
"0x23CC9a102eEe541d468B5F55d6dE1753fB245430" 1000,
"0x58650c16afbD187686aB4D55B4AD9bf6191fefF2" 1000,
"0xa59959D7DaaD25fd25781b7CEBcfd4303434e868" 1000,
"0xA43680F8E8694bedE9F2050920C2bfcb8687329c" 1000,
"0x3Bb65357828Bd88457DA57cC7f144D004d3B036B" 1000,
"0x8f6C1E30079535e45900Fd525fFA8BA1225F0EE8" 1000,
"0x15E6a4EF615198d25a34DAFAe24446011400bedD" 1000,
"0x6F9cb16EBcEB99cf88ac97c3E35698E0e3D48F47" 1000,
"0xea9C95FB771De9e1E19aA25cA2E190aE96466CDD" 5000,
"0xDBfd04666F46Fc8CCadA187AD5Ecb736c0d09657" 1000,
"0x73a95DCa7522b9319a46f723Db44AF0c2F2cCe7c" 1000,
"0xC49827499FD8dEebD14f6AC117022C99F99a2Ddc" 1000,
"0xeD523745Ac4D3b9313045C7d2238EdC2dFf50781" 1000,
"0x812585402c94D4a4Fe0fa98FC05a4c2A404B05A7" 1000,
"0x3b630662cf15B0280A45bE85f1a175D5D8ED4939" 1000,
"0x8911323De6b42df0bb9bD43d21e1D2E0C9236839" 5000,
"0x0025a54871Dc1FBa33da0212453094f73Cf64066" 1000,
"0x65fac207ee655c873b5dcaae9a8d4140b15ec81e" 10000,
"0x7e229c415ef56f8ea9ccca7291e88f0b3fa2bdcc" 1000,
"0xb1b49Cd4Df741C883073c4f54f23921d6f2662C8" 1000,
"0xd98b8BA6bEcf3694A8BDeBA0c9e9B1918E5C0CD8" 1000,
"0xc893c331A99Ec7A0CC186DFeD7F1F6E06a1A943F" 1000,
"0xd26bE7916836AECA8a7Cb41ef2f1e4299469f35D" 1000,
"0x7dAfD53AEE8982aB1D767830c2fe50f62E3a98E6" 2000,
"0x700694817BB4C7431ee19b51a002b062C6De7F80" 1000,
"0xdC1Fe37a00909ad34A827A377eBC184b897b8910" 1000,
"0x394B6a2a8ebc8Da4716F67a5F61ebe6f8d31C50A" 1000,
"0xF6825F6B83677ed6353c31B01BCe8363a2cCdCF3" 1000,
"0xf21749506CDC7C684b096bA172c99A8878a816FB" 5000,
"0x7Ee084006b6Aea591DA21E26444915Fb57Ed647E" 1000,
"0xFE88DD131d675874d8475ED6d3E3e92993f76d51" 1000,
"0xaB99F2AbA7d6CA4E61148a181036cfc84c680cb8" 1000,
"0x456D5C6c0322869e0e2beaad13819e7CA55D8006" 1000,
"0xA26776bC0d2079e550987F351969C727925FF6f9" 3000,
"0x564257bd12F17E3bcf0F3504FE0F5C8386254c39" 1000,
"0x6CF176CfcC5b82D5b14af25CF09bf3D6D37E1716" 1000,
"0xa8B4d876cDB3dD4f066FD830A21464daf8857c80" 1000,
"0x30398e0f9e53475eefb5d60a52a048a2dc47709a" 1000,
"0xeC92519007b823765664Beac13eFAF630C263316" 1000,
"0x019a5e8314d7273640cEf5675Cbfee834F4020C5" 1000,
"0x8e283225172CA64bfd44AC8D27CCf8728f5c2735" 1000,
"0x0a94bcc0D0eC042CeD861d4D228bf8414B1d2956" 1000,
"0x7dD16CCa04E09C925D248AefEDa0c37cB76c7E16" 1000,
"0x0061b82814878024452427f8087733aE46a5a61a" 20500,
"0x1021F3AA2F1e8aBcf01c374305022b4B6e62135b" 1000,
"0xa0298d6163B8f1d2594CB7C0dFa5359d4238f696" 1000,
"0xA7bd17Ac3082a281FfAa2730f361E5c596224eaa" 1000,
"0x03118e02cE007a0F0d1C9D806c2a7D5Ae2F26995" 3000,
"0xf74c902f38e25a50464cccd24fdf94438dbd5d24" 1000,
"0xE6A9B3D0C232B5866ba0b90F0e3711AeF6E1D382" 1000,
"0xf8536CA7a25CBF70DF754fA310079aDa4c6114C2" 10000,
"0x0b48689A46F89b8149851021666CEa967902fc0C" 1000,
"0x24D39ecbDbBf850A13BD281827CFe6ada211b175" 1000,
"0x6ed95B6fc786D426789Ff42b7d754fC26667bfAc" 1000,
"0x8635E9bBB8d628958787c227db6A3E070B9429dC" 1000,
#_ #_ "0xfC8b7d3405F68B07A84CC24caF79430f06618D8d" 3000,
"0x54243AcE4f7B5f333090da5725082D857f914A18" 1000,
"0x88E347aABCa0Ff031ef52937C6D56a7a6E4b0475" 1000,
"0xae17ebd7f3bb7f74340647f68304fba0dcb7aa1d" 10000,
"0x041DeDfeC783D8D6D8BD4f81Cb3675042151184D" 1000,
"0x18Fa802F9AA92CFfbd45f51e208a7D636612d65a" 1000,
"0xeaa40F6B29CE35d8F53f6bF9b2A7397E3D8475Af" 1000,
"0x15ff63d544ecB4a24969121b2F3239867D4F18E4" 1000,
"0x3463DE8E9F42798C75492fE26273680F0fF0262C" 1000,
"0x3592C46b40123Dd9ac242e37a94F4C8C082df439" 2000,
"0xeAFEDde19F9c37e44f1Ec91487003Fdf895DdA3F" 1000,
"0x70f421ca5D3263e82c155075a14EbCB7e5336643" 1000,
"0xa10Ce005fcdb49Ab04E05fdFE15539deef774fF3" 1000,
"0x1ad89A2B5537feF9799B64469E5f712F2d01a43E" 1000,
"0x6e1323eF2554633375dC1D81696F9BA6fB18A2F5" 1000,
"0xEd289a040f4e80FdD8D1065Eb9F4482b5bEe7A60" 1000,
"0xb45489842B2F99e96f66a6eB486ae9c4F54A47c9" 1000,
"0x745E6bDDD3024E73daEc30d883A0A4e21D728cD9" 1000,
"0xbb7730b90273D8ccd1Df142C712a864f4401CC78" 1000,
"0x665EaD9D831423e362D11BEaE3b9Dba380B8083A" 1000,
"0x88Bdb0aeC80e001738c101d111EE035F1eaC0D95" 2000,
"0xA8E85dEe96F33Af3f5faae887dDf19260aDA2Ac7" 1000,
"0x15EF0B50823C0c96EF201CB418E3785F6b8D7D59" 1000,
"0x90e7aA0a9f37fa3930c1D33D57893E3372C84773" 1000,
"0x85c7716158d1050c918eb5859c5219fac0665eb7" 1000,
"0x8E765AF6b5366A1c073600c1951C8998BF11ffa2" 1000,
"0xd2E8bdCE6dc933eD4eEFcf7b069653F54823D3Fa" 1000,
"0x3ac6cb2ccfd8c8aae3ba31d7ed44c20d241b16a4" 25000,
"0xB7FeA0028b8EC4a0B651B060f58565EB6C57D507" 1000,
"0xd17597f94ac4841ad8f24a2c222a3a056ad2116a" 25000,
"0xf16CFD73Fe21E1d2ffdC68C6348489AD917e8546" 3000,
"0x30b7908a77c07d1aE480d26D5039Ed01049AE1bf" 1000,
"0xcdAA0072029E8c3e8C46c5Ed6c274cA6EA335a28" 20000,
"0x2aC079a959e3ca41B2cd5457b07930ABEB800943" 1000,
"0xBc55Cd5499DC8034f3e98a31D44421e4B16D6CBB" 1000,
"0x5ed1ac26ee940a42207955e119d283ecfe18a477" 25000,
"0xF38852A25c1e3557D876e88E2FEE3522eFe03E96" 1000,
"0xc8e7E9B4335Ec38b1eF2c72274eBc530bb806B3c" 1000,
"0x2827d3f9C39bA0507710A0D813f8A1b2EC9d3C07" 1000,
"0xFFf94042354Cf1ffEEC622E4563774390c999dC8" 1000,
"0x78CAc1584824dd9633d71f9EF41B56e6AA9927c0" 1000,
"0x6F0bECd0348CacAe43Ecd0f09805885675F51124" 2000,
"0xD38828D80aC4E5CF5F4A102494816945Ea37FB7B" 1000,
"0xd4536721D929d66d645D6E6550aA06d8A82A95c6" 1000,
"0x6308f9536c177059cFc4D78a1c8814a128Ce29D9" 1000,
"0x4838eab6f43841e0d233db4cea47bd64f614f0c5" 25000,
"0xeBcf2E9FAacB281c947A81759847139AE0Ad3992" 1000,
"0x3BBb5a4b05B8241ebB268c605541580270A2f3f5" 18000,
"0xf3B44AC5491E5349894D01532cDaeBa13311C041" 1000,
"0xcea47EbD1e877fc651e72004e6C2F8bA8Bff3bC9" 1000,
"0x03b12981Ef4dF9bd810Ae12C53230BE9848AE5A5" 1000,
"0x2a57B99146fd06976C45F937604F0a19041938EA" 3000,
"0xa386563bf026eEBe096fe26acc6e80Ba84D213a2" 1000,
"0x3Ab76b9AF7da268A2dcAE0c2241fC37654d6DBea" 1000,
"0x76e5fFFc26386E4D617eD6DF7Be9596f4007fCae" 1000,
"0xc31Bcd3Fd846518B91669727de9cb8fccF07bCba" 1000,
"0x910418Bc7839A456ba268E1D891d43AC6DD51AD6" 1000,
"0xcF876a3deF89b6e3DE37974190C843A83ACF090e" 1000,
"0x869e5B1bA479179f97D110D1D87f8E6dc7eB64Ae" 1000,
"0x310Bc5f5746f7749eCdBBa01B4EAbC6F1A9a0E18" 1000,
"0xDb25E5f07d8607823Fe76407046B0e469aCA164d" 1000,
"0x863Be577Ebff3fc3094cd6D91c8eFa54d077c821" 1000,
"0xFd2262c369636E1c295C9aBA4CaD67316FBa74A2" 1000,
"0xc83585b0Bf139A392069eE22C14dd4D64D26079A" 3000,
"0x0a417Def3B61404122c7580bfF82dc97E8a86D85" 25000,
"0xc0B8705d2c92D7AfAD37cf7885b19eA60a9a1a71" 1000,
"0xa2dEE84501a30b5847EcfEf8DB22a726EE911346" 1000,
"0xA92b2b995a6a09097a243dEbD79DcFC2B46848Ed" 1000,
"0x4eF6f3A56Ce63753EE82DD6e6654EaB912F7cECd" 5000,
"0x25619749e040dec6a6832d60d228f867dd77c35d" 1000,
"0xB7f1498898d70685851B5331F64bF26215f00415" 1000,
"0x5B17e67DAD94A65759B2e9555D8dA6A2B8db6BE7" 1000,
"0xF34c0e5346cF57867A661e6B34ede6135d38bb85" 1000,
"0x7ec7b7FE8F255B3909313A37DdbFf407BF56F29e" 5000,
"0xa91A30500A60258dC83F08bD7E29086F19E75E10" 1000,
"0x24Cb28f325A9CE3C27D746e70Edeb9643f37c86E" 1000,
"0x67936306c1490db7c491b0fe56bcf067ede1fd28" 1000,
"0xB00C946c53ab3b51F73C5DF7fcd10b39073e1790" 1000,
"0xAe16d2f23e2389D3E60345AF20631Db806024C16" 1000,
"0x47dd3D9c9843f71eEDb4CdEA4ceB07E55B06adA0" 1000,
"0x1F58868b6fA873739A07cB8D0412108Dc3B01733" 25000,
"0x7eB1e9267Ab19cefE7Dc068Be6c8f9dE42b0d85E" 12000,
"0x42c163Eff7D309425487CE50a9f4cB91DA19e4d1" 1000,
"0xbCCc76522169bF83078aee30a509c32909D9AEa2" 1000,
"0x2116Bc455dDf345539a738fdE43ABb63e6B0061C" 1000,
"0x1B5E3A4B53E1fFF879C718DE6afD45e4AFA6eF49" 1000,
"0xDd3b9BE91EA4D427e62c3fA3f2B27b5290d98F1e" 1000,
"0xb6b81bbFE61a1Cf3F9a8E8514D5E0F7200CfCcA2" 1000,
"0x106C21874eaA24d3bF34139281Ae5f1a82A101b6" 3000,
"0xD4072DccceF9e050d29043e680f2574868C31021" 1000,
"0x290Dbf7EB51324266F0668675a2a230d250b293C" 1000,
"0xc49d1085e06a93cD0F95dbD3C4e270Db7aB8f572" 1000,
"0x6C441eBA0ac23897B58c342f36a2D9a214593DdB" 1000,
"0xE49eA037c47F4eb9b6e434B65902B759FDB08Bbe" 1000,
"0xB7426E85Ca3eC67a009d30558062dda387cDb412" 50000,
"0x7ABCcb7afc349851d2f4E1D31A1f9DBd0e5F2F45" 1000,
"0x5bB91b0b19E06ee8411431726F0c9661b1782070" 1000,
"0x52bB24A71aAb5f2DC01Aa1C8730aa27d9548Cd3a" 1000,
"0x4a44dd1f701a90325513cad8a37d21f80dcc1da1" 1000,
"0x04DDA39c62312aE8b23bB4C36a703576C009327B" 1000,
"0xa3115D531b75BC72c796Af207192Fc960b615783" 1000,
"0x792A57BE9b0E40E7bf2970Db901e5Ecd2DE30B7d" 1000,
"0x624DAeF5eA222Aad86d1a17EF72728169bDB360d" 61000,
"0x0e0CD189eC770A2814E78c9c9b022abdd5174723" 1000,
"0x0ddF6E4172fDd4D0389De04Bd440330FFC0eB96E" 1000,
"0x611ec96B4dF9c8bbDB0258858C8451cAFedfDA34" 1000,
"0xc7f148f442d5d76F2831A3053033E56F7A7573d3" 1000,
"0x6a297d402907dC13D292000feD490099024C822a" 1000,
"0x8B0BCaf9f6c7b18810Eb412E08241659a20aDfd7" 1000,
"0xb5A378c1Fd1F31f1077C89f448deE3488d81669D" 1000,
"0xabb4639de78e88dabf47b8d659574dd660ffbb2c" 1000,
"0xa463F6edB92a2D7b9c90afc20a5Ce2116a945164" 1000,
"0xd5ff18c05fb0aa587aadef87c8a8facc0d417b9a" 1000,
"0xfee48cEc41f071Bc462507d1E2fDa9B2fADB39C2" 1000,
"0xF2f962ad05aEe8069B6e1e2AcE6E0C4b1414dF97" 1000,
"0x7A3D3C991506432e09E05dB9cBeE8329e1067cAd" 1000,
"0x7E5d729704263f71D82fe2F8fC127526dddbC36C" 1000,
"0x0fa38abec02bd4dbb87f189df50b674b9db0b468" 1000,
"0xA7921Bb5389368C3B9C55605826Ed5c7656F0313" 1000,
"0x9ca99bC90bc7C8F393848f4ff220e57202949654" 1000,
"0x09ECb548371278A4fEE5E8e9B9bF1596F85d02c8" 1000,
"0xf705CeB0f8b700d98978D5fC91F7705169e3e60e" 1000,
"0x1e1cCD5EC07e2D63e50ef2b183B66dB444C9f845" 5000,
"0x53e49353D37ad53CafFB4698CD9B7d831f55F707" 1000,
"0xBffB814b73801Ff822427a3d8B902dbc8fFb5F93" 1000,
"0x2A8392859b3eF08659af44fBCABaD3BDE170f4C7" 1000,
"0xCb0ff21Aaf4CBC57B1B7EfBADbbd96D16ff50E57" 1000,
"0x185c742082316a46C0736c16F75332126F9c43d3" 1000,
"0x5C35A34977f83E049bd699e2481e21D116223B04" 1000,
"0x9cd6a59a40b7a88512999afc90220e5942e182ac" 1000,
"0xaf24Ba021B3e8D3a13b4691a2B0828dCd811545E" 50000,
"0x09DB255Cd4e9927264391c87A6572338be33E08A" 1000,
"0x4D93604b66261116c9aac3E5d3e954BfEadA3a5D" 1000,
"0x95c96042D5d3941DeB785EbabD313EB317717E45" 1000,
"0xA9501D1f52CA501ee432d62C6d89Cb77276FdfCe" 1000,
"0x55B39B67BB496B5E9F057Cde5E9F5173dCC66ADE" 1000,
"0xcfd0055e61e4061052b77e51c8ce58e7a390bb90" 1000,
"0xA9e2eFFBb7006c9E380FBda884EE316fC40F9cDD" 1000,
"0x12040482Ab34ACbB440b17c64e7EB72253FD1401" 1000,
"0x00049808dcce781C7FD603B9a2563c0932Ef6d29" 1000,
"0xE72CE789BF6393771aa454e09Cd5be9715a83474" 1000,
"0x4A70EE052822A4571642769dEed715D4bBABd3f8" 1000,
"0x0646F493FAC83c393A3b3B76669b52eDE6Ec5774" 1000,
"0x59207cFeDa73D3B9Cb297d187446C7189D8e2bDC" 5000,
"0x03439743652496291b17DDdBa5a93b9D8B9EB20D" 1000,
"0x4549DF8057aa166368aAAb2fe7af0AC2F1B6B01E" 1000,
"0x39f4662bf97200dbfa00ed05e3141c8959151cfa" 3000,
"0x057b0175E2eD09CA783BC33C48cF31615B233692" 1000,
"0xf25f1E156b5D329389eD7641A7a7012eAeb3172f" 1000,
"0x8966FD4A3091C8c031F53Ad150a68D9235265EA7" 1000,
"0x2ee16239cfefc5e5f657e0aecc53b3643656dfa9" 1000,
"0xED2fd9b1bBb02a4cFa167942F771f7CFb522A0E6" 1000,
"0x37b9907d267Ad0D852A0490e77d37BE9A896c4A0" 1000,
"0x9df1FCB2dcCA866bEdfb6514d3D5a1eBD522A544" 1000,
"0xa22D548B393736D0470584cCeE0cd59A90E15bBd" 1000,
"0x28C2897122286A35738413E264942a781AF5c06A" 1000,
"0xa06d7BA83c7489716c9bA4429766D5Db8DeDC942" 1000,
"0x00304C9D754Fa9B897Aa655D531AE125b7a12108" 1000,
"0x072C075612aF238B2184CdcBc379B78eC048F918" 1000,
"0xD9f3465E42B5F0eC627A156FB158b32Bc828CBB" 5000,
"0x6E04454F2bb9D04F505C8b775E2e68cFc95F46D2" 5000,
"0x2fd4EC45ec04d33127E59CDfF2be4AC6d0B8C976" 2000,
"0x8CD0C09B71a76298cE90459524883663C88D063F" 1000,
"0xa1C78ED146a8693A8cF3d29385BC54Cd3F145B4a" 10000,
"0x6E258688b739ebdB1F2Dcc4fbf7D96d0fa6Cacff" 36000,
"0xd4499ded424CA4d068D2f6B5eCf3d645D8e166ea" 1000,
"0xaa8c09A4eD08B97F5886E067eA203656639ADfBc" 3000,
"0xc71a4798DBB8b85Db9e1b697B233F826B4F93dde" 10000,
"0x2ba61dA3E9b2eB86879373EE337C1730990BacEA" 1000,
"0xe4ef526473accbfc617451010beb5fbd68fe816d" 1000,
"0xACFe2fDdd3Ff10A5f9b0b2bbb581BdeCB8EA0287" 1000,
"0x4161e7f10852b74713099Ca1a0Bd47fe341e5B52" 1000,
"0xbD6221808d98b601d343aC0aC7C0379F28399bde" 1000,
"0xd046Cd27126d4f22C83Ba1d7C393d9b9A976f269" 1000,
"0xa5ed3807e915973d11947E26E742b6d6b8d05506" 20000,
"0x2D99B9B9Afc29dC2caB888C1E7928C7b131e4656" 1000,
"0xc8f1E7FF0E5066C8d8638575dBaD7CB261f19819" 1000,
"0x758f338534754eE7ea76a234332BA5EB695B2347" 1000,
"0xAff4f80ED19fA3b5856472362d77Dc87061aB932" 1000,
"0x924De4EFaC18ed4460C0b93d3bF726788E1a3F22" 1000,
"0xd5d28bbe1d2563addFaB1900F9dD7778cA515A9e" 5000,
"0x41E53CD6Eb57CDb25ACE7eeBd212178cD358D48e" 1000,
"0x9cbb422df9f16B925dD1fd48b82073Be4f740496" 1000,
"0x5e51f674239f938110417a75e3f89d03d566b9ed" 1000,
"0x5A1495fAB6a150D9D0989B49e69bcD24F5fc243d" 1000,
"0xcA83fC54849e9a200b4401134B391E83b8D03ACF" 1000,
"0x424ce77Aff0D95615dA060bD3f8D570F774d633b" 1000,
"0xE71E66E9A1a53dBB9488C50b5bc08289afEF85f5" 1000,
"0xB2839c0Fb42E66D8bAE27C2A0EAE5807e95e612A" 1000,
"0x00ed6b3e01d2edafdefe598a7d962bbc7526629b" 5000,
"0x65ed0C1Ead5383988e556027Ac81F1acAD8d6A10" 1000,
"0x00ae0c1fd293038C2b24a715E6fAbAcDa6012b55" 1000,
"0x6765579e9750670d5bF03F4DAcCF21aFd691b0cF" 1000,
"0x13A33bB5321c1cb27C3F7011A9fFf1Dd5E660e74" 1000,
"0x08b55C4D3b0959D6F11fB3534970357765E16495" 1000,
"0x3eA10564417AdB679d149c2F4A3D118b0123e72D" 1000,
"0x015E395AaA541574ea7b33A7803F67374C11c129" 1000,
"0x06905127EcB3f59c46a468489e5b262d7AfCc2e8" 50000,
"0x21Ac5f731b2AaFb6d7CcD20c1a70d5dFE320AEeb" 6000,
"0x5e9ea9d04bff6e5416e5cd59d750293d4e186639" 5000,
"0x2Bc7e8EeC35CCB4644199Fd2C881eA8Da98a0cA9" 1000,
"0xa4665c4524f09320b60f460c12DD943AacaD1b4b" 1000,
"0xEd5830604989CcE0D9A3E97ECD84f3a66Df93bFe" 1000,
"0x86b717A8E106Ab0A84b6e1a3E47aBc60F643C81a" 1000,
"0x05FFDec848E8Ca0AB751748A2cE3bf6bbAB91b24" 1000,
"0xB7BE0712d6ea427cE952539B52B0d10ea9a994b4" 1000,
"0xCC5479F7A6Cd4dCAA0F0fEd16E7952709ba1dC09" 1000,
"0x3785d73c25C4c08dC2c40fbA1CC845Fdc2210732" 1000,
"0x9C520c675BEB6eA07Aaf6F850a6Bc4Cd0724b015" 2000,
"0x9c2238E76e267912EDB7817ce2C6E13468759110" 8000,
"0x19E580c6230b9194A7A0935ed4217CfFe8278adF" 1000,
"0x98D5F2d180a811e1Ef17a2b3D501242d0a714eE7" 1000,
"0xffb5d974cba1e8c3761427f017c9666c9f14c32b" 10000,
"0xE68eDa08389E8642E7b13Fc2e783f41150830a02" 1000,
"0xfB9E00A0ADC832F82631a2D6f5467D802296249D" 1000,
"0x004DccdCCd989fE30Ebb6ABc304cEBeCa438fa2b" 1000,
"0x8ae03Fa94a53128AeCaAA3dfFB87FcA97797c1F0" 1000,
"0x1d186680fea0c552ff4ed9F0bDCa1629e2EA1528" 1000,
"0x90cc6AD2f24209a127dD6247bf68acC0a453f2BF" 1000,
"0x583a22c4B14ae27ff4d25e9F1a2448ea9cce199a" 3000,
"0x8C3EaC201Ae1644eb6dA0F9318a2FF9C5F0c6D20" 500000,
"0xF8be4E6e786c4248b6dF08c5B766d786AE905B36" 1000,
"0xBF9B1c552C1fDEeDcB6a05F5C3db563bBE10B4bb" 1000,
"0x8d2548cec0ac6807c0131e33360ad6e1332fe929" 1000,
"0x0a4231157671A451F1919d87f38bd0C307A0960F" 1000,
"0xDF90a56FeDE1dD8c2F89060dc8d649CAe1A026fC" 1000})
(def contracts-version "1.0.1")
(def current-contrib-period 0)
(def min-contrib-amount 0.1)
(def contrib-period->name
{0 "v0.1"
1 "v0.2"
2 "v0.3"})
(def disallowed-countries #{"US" "BA" "MD" "RS" "ME" "BY" "CI" "CU" "CG" "CD" "IR" "IQ" "LR" "KP" "SD" "SY" "ZW"})
(def scammers #{"0xfC8b7d3405F68B07A84CC24caF79430f06618D8d"
"0x9df1FCB2dcCA866bEdfb6514d3D5a1eBD522A544"
"0x2ba61dA3E9b2eB86879373EE337C1730990BacEA"
"0xd918219fd9bE2DE265438128988A0716C2BE1236"
"0xe35c3F2211F9A0dC3883338Bc50A84DD16cb4cc2"
"0xB00C946c53ab3b51F73C5DF7fcd10b39073e1790"
"0x989943F1DF0874e5735b6ec2fa4d221384CbB067"
"0x03439743652496291b17DDdBa5a93b9D8B9EB20D"
"0xfB9E00A0ADC832F82631a2D6f5467D802296249D"})
================================================
FILE: src/cljs/contribution/core.cljs
================================================
(ns contribution.core
(:require
[cljs-time.extend]
[cljs.spec.alpha :as s]
[cljsjs.material-ui]
[cljsjs.react-flexbox-grid]
[cljsjs.web3]
[contribution.components.main-panel :refer [main-panel]]
[contribution.constants :as constants]
[contribution.db]
[contribution.events]
[contribution.subs]
[district0x.events]
[district0x.subs]
[goog.string.format]
[madvas.re-frame.google-analytics-fx :as google-analytics-fx]
[print.foo :include-macros true]
[re-frame.core :refer [dispatch dispatch-sync clear-subscription-cache!]]
[reagent.core :as r]))
(defn mount-root []
(s/check-asserts goog.DEBUG)
(google-analytics-fx/set-enabled! (not goog.DEBUG))
(clear-subscription-cache!)
;(.clear js/console)
(r/render [main-panel] (.getElementById js/document "app")))
(defn ^:export init []
(s/check-asserts goog.DEBUG)
(google-analytics-fx/set-enabled! (not goog.DEBUG))
(dispatch-sync [:district0x/initialize
{:default-db contribution.db/default-db
:effects
{:async-flow {:first-dispatch [:district0x/load-smart-contracts {:version constants/contracts-version}]
:rules [{:when :seen?
:events [:district0x/smart-contracts-loaded :district0x/my-addresses-loaded]
:dispatch-n [[:watch-dnt-balances]
[:district0x/watch-my-eth-balances]
[:contribution/get-contrib-period]
[:contribution/get-configuration]
[:contribution/setup-event-listeners]]
:halt? true}]}
:district0x/dispatch [:load-ip-location]
:dispatch-interval {:dispatch [:update-now]
:ms 1000
:db-path [:update-now-interval]}}}])
(mount-root))
================================================
FILE: src/cljs/contribution/db.cljs
================================================
(ns contribution.db
(:require
[cljs-time.core :as t]
[cljs-web3.core :as web3]
[cljs.spec.alpha :as s]
[district0x.db]
[district0x.utils :as u]
[re-frame.core :refer [dispatch]]))
(s/def :contribution/stopped? boolean?)
(s/def :contribution/founder1 (s/nilable u/address?))
(s/def :contribution/founder2 (s/nilable u/address?))
(s/def :contribution/early-sponsor (s/nilable u/address?))
(s/def :contribution/wallet (s/nilable u/address?))
(s/def :contribution/advisers (s/coll-of u/address?))
(s/def :contribution/max-gas-price u/non-neg?)
(s/def :dnt-token/transfers-enabled? boolean?)
(s/def :contrib-period/soft-cap-amount u/not-neg?)
(s/def :contrib-period/after-soft-cap-duration u/not-neg?)
(s/def :contrib-period/hard-cap-amount u/not-neg?)
(s/def :contrib-period/start-time (s/nilable u/date?))
(s/def :contrib-period/end-time (s/nilable u/date?))
(s/def :contrib-period/enabled? boolean?)
(s/def :contrib-period/cancelled? boolean?)
(s/def :contrib-period/soft-cap-reached? boolean?)
(s/def :contrib-period/hard-cap-reached? boolean?)
(s/def :contrib-period/total-contributed u/not-neg?)
(s/def :contrib-period/contributors-count u/not-neg?)
(s/def :contrib-period/stake u/not-neg?)
(s/def :contrib-period/loading? boolean?)
(s/def :contribution/contrib-period (s/keys :opt [:contrib-period/soft-cap-amount
:contrib-period/after-soft-cap-duration
:contrib-period/hard-cap-amount
:contrib-period/start-time
:contrib-period/end-time
:contrib-period/enabled?
:contrib-period/cancelled?
:contrib-period/soft-cap-reached?
:contrib-period/hard-cap-reached?
:contrib-period/total-contributed
:contrib-period/contributors-count
:contrib-period/stake
:contrib-period/loading?]))
(s/def :form.contribution/contribute (s/map-of :district0x.db/only-default-kw :district0x.db/submit-form))
(s/def :form.contribution/enable-contrib-period (s/map-of :district0x.db/only-default-kw :district0x.db/submit-form))
(def default-db
(merge
district0x.db/default-db
{:load-node-addresses? false
:node-url "https://mainnet.infura.io/" #_"http://localhost:8549"
:smart-contracts {:contribution {:name "District0xContribution" :address "0xf8094e15c897518b5ac5287d7070ca5850efc6ff"}
:dnt-token {:name "District0xNetworkToken" :address "0x0abdace70d3790235af448c88547603b945604ea"}
:mini-me-token-factory {:name "MiniMeTokenFactory" :address "0xa7dd95d9978dde794eae5233889f1ffebcdc9914"}
:multisig-wallet {:name "MultisigWallet" :address "0xd20e4d854c71de2428e1268167753e4c7070ae68"}
:token-vesting {:name "TokenVesting" :address "0x7c715A0d3018e254CC6A1c699bc63aBBaAeA5B7e"}}
:now (t/now)
:admin-addresses #{"0x8F5aAfdE2f96238e88403a9aF533F7D0440309f4" "0x610cAcfCc86Fe4B7A6c99F7FA0f49Dd6725c6632" "0x2Db0aaF01876d231E1541f72FB50b8c6716FCc9A"}
:disallowed-country? false
:confirmed-terms? false
:confirmed-not-us-citizen? false
:confirmed-gas-price? false
:confirmed-compensation? false
:confirmations-submitted? false
:dnt-token/transfers-enabled? false
:contribution/stopped? false
:contribution/founder1 nil
:contribution/founder2 nil
:contribution/early-sponsor nil
:contribution/wallet nil
:contribution/advisers []
:contribution/max-gas-price 0
:contribution/contrib-period {}
:form.contribution/contribute {:default {:loading? false
:gas-limit 200000
:data {:contribution/amount 1}
:errors #{}}}
:form.contribution/enable-contrib-period {:default {:loading? false
:gas-limit 100000
:data {:contribution/period-index 0}
:errors #{}}}}))
================================================
FILE: src/cljs/contribution/events.cljs
================================================
(ns contribution.events
(:require
[ajax.core :as ajax]
[akiroz.re-frame.storage :as re-frame-storage]
[camel-snake-kebab.core :as cs :include-macros true]
[camel-snake-kebab.extras :refer [transform-keys]]
[cljs-time.coerce :as time-coerce]
[cljs-time.core :as t]
[cljs-web3.async.eth :as web3-eth-async]
[cljs-web3.core :as web3]
[cljs-web3.eth :as web3-eth]
[cljs-web3.personal :as web3-personal]
[cljs-web3.utils :as web3-utils]
[cljs.core.async :refer [! chan alts! timeout close!]]
[cljs.spec.alpha :as s]
[clojure.data :as data]
[clojure.set :as set]
[clojure.string :as string]
[contribution.api :refer [parse-get-contrib-period contrib-period-args parse-get-configuration]]
[contribution.constants :as constants]
[district0x.big-number :as bn]
[district0x.events :refer [get-contract get-instance all-contracts-loaded? reg-empty-event-fx]]
[district0x.utils :as u]
[goog.string :as gstring]
[goog.string.format]
[medley.core :as medley]
[re-frame.core :as re-frame :refer [reg-event-db reg-event-fx inject-cofx path trim-v after debug reg-fx console dispatch]])
(:require-macros [cljs.core.async.macros :refer [go]]))
(def interceptors district0x.events/interceptors)
(reg-event-fx
:load-ip-location
interceptors
(fn [{:keys [db]}]
{:http-xhrio [{:method :get
:uri "https://ipinfo.io/json"
:timeout 20000
:response-format (ajax/json-response-format)
:on-success [:ip-location-loaded]
:on-failure [:district0x.log/error]}]}))
(reg-event-fx
:ip-location-loaded
interceptors
(fn [{:keys [db]} [{:strs [country]}]]
{:db (assoc db :disallowed-country? (contains? constants/disallowed-countries country))}))
(reg-event-fx
:update-now
interceptors
(fn [{:keys [db]}]
{:db (assoc db :now (t/now))}))
(reg-event-fx
:deploy-contribution-contract
interceptors
(fn [{:keys [db]} [contribution-args address-index]]
{:dispatch [:district0x/deploy-contract {:address-index address-index
:contract-key :contribution
:gas 3500000
:args ((juxt :contribution/wallet
:contribution/founder1
:contribution/founder2
:contribution/early-sponsor
:contribution/advisers)
contribution-args)
:on-success [:contribution-contract-deployed]}]}))
(reg-empty-event-fx :contribution-contract-deployed)
(reg-event-fx
:deploy-mini-me-token-factory-contract
interceptors
(fn [{:keys [db]} [address-index]]
{:dispatch [:district0x/deploy-contract {:address-index address-index
:contract-key :mini-me-token-factory
:gas 3000000
:on-success [:mini-me-token-factory-deployed]}]}))
(reg-empty-event-fx :mini-me-token-factory-deployed)
(reg-event-fx
:deploy-dnt-token-contract
interceptors
(fn [{:keys [db]} [address-index]]
(let [contribution-address (:address (get-contract db :contribution))
mini-me-token-factory-address (:address (get-contract db :mini-me-token-factory))]
{:dispatch [:district0x/deploy-contract {:address-index address-index
:contract-key :dnt-token
:gas 3300000
:args [contribution-address mini-me-token-factory-address]
:on-success [:dnt-token-contract-deployed]}]})))
(reg-event-fx
:deploy-token-vesting-contract
interceptors
(fn [{:keys [db]} [{:keys [:beneficiary :start :cliff :duration :revocable?]}]]
{:dispatch [:district0x/deploy-contract {:address-index 0
:contract-key :token-vesting
:gas 3300000
:args [beneficiary
(or start (time-coerce/to-epoch (t/now)))
cliff
duration
revocable?]
:on-success [:dnt-token-contract-deployed]}]}))
(comment
(re-frame.core/dispatch [:deploy-token-vesting-contract
{:beneficiary ""
:cliff 0
:duration (t/in-seconds (t/days (* 365 2)))
:revocable? true}]))
(reg-empty-event-fx :token-vesting-contract-deployed)
(reg-event-fx
:deploy-multisig-wallet
interceptors
(fn [{:keys [db]} [{:keys [:multisig-wallet/owners :multisig-wallet/required]} address-index]]
{:dispatch [:district0x/deploy-contract {:address-index address-index
:contract-key :multisig-wallet
:gas 3300000
:args [owners required]
:on-success [:multisig-wallet-deployed]}]}))
(reg-empty-event-fx :multisig-wallet-deployed)
(reg-event-fx
:contribution/set-district0x-network-token
interceptors
(fn [{:keys [db]} [address-index]]
(let [dnt-address (:address (get-contract db :dnt-token))]
{:dispatch [:district0x.contract/state-fn-call
{:contract-key :contribution
:method :set-district0x-network-token
:args [dnt-address]
:tx-opts {:gas 300000
:from (if address-index
(nth (:my-addresses db) address-index)
(:active-address db))}
:on-tx-receipt-n [[:contribution/get-contrib-period]
[:contribution/district0x-network-token-was-set]]}]})))
(reg-empty-event-fx :contribution/district0x-network-token-was-set)
(reg-event-fx
:contribution/setup-event-listeners
interceptors
(fn [{:keys [db]}]
(let [contribution-instance (get-instance db :contribution)]
{:web3-fx.contract/events
{:db-path [:web3-event-listeners]
:events [[contribution-instance :on-contribution {}
"latest" :contribution/on-contribution [:district0x.log/error :on-contribution]]
[contribution-instance :on-soft-cap-reached {}
"latest" :contribution/on-soft-cap-reached [:district0x.log/error :on-soft-cap-reached]]
[contribution-instance :on-hard-cap-reached {}
"latest" :contribution/on-hard-cap-reached [:district0x.log/error :on-hard-cap-reached]]
[contribution-instance :on-emergency-changed {}
"latest" :contribution/on-emergency-changed [:district0x.log/error :on-emergency-changed]]]}})))
(reg-event-fx
:contribution/on-contribution
interceptors
(fn [{:keys [db]} [{:keys [:total-contributed :contributors-count]}]]
(let [total-contributed (u/big-num->ether total-contributed)
contributors-count (bn/->number contributors-count)]
(when (< (get-in db [:contribution/contrib-period :contrib-period/total-contributed])
total-contributed)
{:db (update-in db [:contribution/contrib-period] merge
{:contrib-period/total-contributed total-contributed
:contrib-period/contributors-count contributors-count})}))))
(reg-event-fx
:contribution/on-soft-cap-reached
interceptors
(fn [{:keys [db]} [{:keys [:end-time]}]]
{:db (update-in db [:contribution/contrib-period] merge
{#_#_:contrib-period/end-time (bn/->date-time end-time)
:contrib-period/soft-cap-reached? true})
:dispatch [:district0x.snackbar/show-message "Amazing! Soft Cap was just reached!"]}))
(reg-event-fx
:contribution/on-hard-cap-reached
interceptors
(fn [{:keys [db]} [{:keys [:end-time]}]]
{:db (update-in db [:contribution/contrib-period] merge
{:contrib-period/end-time (bn/->date-time end-time)
:contrib-period/hard-cap-reached? true})
:dispatch [:district0x.snackbar/show-message "Unbelievable! Our Hard Cap was reached! The Sale is over now"]}))
(reg-event-fx
:contribution/on-emergency-changed
interceptors
(fn [{:keys [db]} [{:keys [:is-stopped]}]]
{:db (assoc db :contribution/stopped? is-stopped)
:dispatch [:district0x.snackbar/show-message (if is-stopped
"Contribution was temporarily paused due to emergency"
"Contribution was just resumed")]}))
(reg-event-fx
:contribution/set-contrib-period
interceptors
(fn [{:keys [db]} [args address-index]]
{:dispatch [:district0x.contract/state-fn-call
{:contract-key :contribution
:method :set-contrib-period
:args (contrib-period-args args)
:tx-opts {:gas 1000000
:from (if address-index
(nth (:my-addresses db) address-index)
(:active-address db))}
:on-error [:district0x.log/error]
:on-tx-receipt-n [[:contribution/get-contrib-period]
[:contribution/contrib-period-was-set]]}]}))
(reg-empty-event-fx :contribution/contrib-period-was-set)
(reg-event-fx
:contribution/get-contrib-period
interceptors
(fn [{:keys [db]}]
{:db (assoc-in db [:contribution/contrib-period :contrib-period/loading?] true)
:web3-fx.contract/constant-fns
{:fns [[(get-instance db :contribution)
:get-contrib-period
[:contribution/get-contrib-period-loaded]
[:district0x.log/error :contribution/get-contrib-period]]]}}))
(reg-event-fx
:contribution/get-contrib-period-loaded
interceptors
(fn [{:keys [db]} [contrib-period]]
{:db (assoc-in db [:contribution/contrib-period]
(merge (parse-get-contrib-period contrib-period)
{:contrib-period/loading? false}))}))
(reg-event-fx
:contribution/get-configuration
interceptors
(fn [{:keys [db]}]
{:web3-fx.contract/constant-fns
{:fns [[(get-instance db :contribution)
:get-configuration
[:contribution/get-configuration-loaded]
[:district0x.log/error :contribution/get-contrib-period]]]}}))
(reg-event-fx
:contribution/get-configuration-loaded
interceptors
(fn [{:keys [db]} [configuration]]
(let [config (parse-get-configuration configuration)]
(if-not (u/zero-address? (:contribution/wallet config))
{:db (merge db config)}
{:db (assoc db :contracts-not-found? true)}))))
(reg-event-fx
:contribution/contribute
interceptors
(fn [{:keys [db]} [form-data address]]
{:dispatch [:district0x.form/submit
{:form-data form-data
:address address
:value (u/num->wei (:contribution/amount form-data))
:fn-key :contribution/contribute
:fn-args []
:tx-opts {:gas-price (:contribution/max-gas-price db)}
:form-key :form.contribution/contribute
:on-tx-receipt [:district0x.snackbar/show-message "Thank you! Your contribution was successfully sent"]}]}))
(reg-event-fx
:contribution/enable-contrib-period
interceptors
(fn [{:keys [db]} [form-data address]]
{:dispatch [:district0x.form/submit
{:form-data form-data
:address address
:fn-key :contribution/enable-contrib-period
:fn-args []
:form-key :form.contribution/enable-contrib-period
:on-tx-receipt-n [[:district0x.snackbar/show-message "Your agreement to enable contribution was successfully sent"]
[:contribution/get-contrib-period]]}]}))
(reg-event-fx
:contribution/emergency-stop
interceptors
(fn [{:keys [db]}]
{:dispatch [:district0x.contract/state-fn-call {:contract-key :contribution
:method :emergency-stop
:args []
:tx-opts {:gas 200000}}]}))
(reg-event-fx
:contribution/release
interceptors
(fn [{:keys [db]}]
{:dispatch [:district0x.contract/state-fn-call {:contract-key :contribution
:method :release
:args []
:tx-opts {:gas 200000}}]}))
(reg-event-fx
:contribution/compensate-contributors
interceptors
(fn [{:keys [db]} [{:keys [:offset :limit]}]]
{:dispatch [:district0x.contract/state-fn-call {:contract-key :contribution
:method :compensate-contributors
:args [offset limit]
:tx-opts {:gas 3500000
:gas-price (web3/to-wei 4 :gwei)}
:on-tx-receipt [:contribution/compensate-contributors-success offset limit]
:on-error [:district0x.log/error offset (+ offset limit)]}]}))
(reg-event-fx
:contribution/compensate-contributors-success
interceptors
(fn [{:keys [db]} [offset limit]]
(println "Successfully compensated" offset (+ offset limit))
nil))
(reg-event-fx
:contribution/enable-district0x-network-token-transfers
interceptors
(fn [{:keys [db]}]
{:dispatch [:district0x.contract/state-fn-call {:contract-key :contribution
:method :enable-district0x-network-token-transfers
:args []
:tx-opts {:gas 500000}}]}))
(reg-event-fx
:watch-dnt-balances
[interceptors]
(fn [{:keys [db]}]
{:dispatch [:district0x/watch-token-balances
{:addresses (conj (:my-addresses db) (:address (get-contract db :contribution)))
:instance (get-instance db :dnt-token)
:token-code :dnt}]}))
(reg-event-fx
:dnt-token/transfer
[interceptors]
(fn [{:keys [db]} [{:keys [:dnt-token/to :dnt-token/from :dnt-token/value]}]]
{:dispatch [:district0x.contract/state-fn-call {:contract-key :dnt-token
:method :transfer
:args [to value]
:tx-opts {:gas 200000
:from (or from (:active-address db))}}]}))
(reg-event-fx
:set-confirmation
interceptors
(fn [{:keys [db]} [confirm-key confirmed?]]
{:db (assoc db confirm-key confirmed?)}))
(reg-event-fx
:reinitialize
interceptors
(fn [{:keys [:db]} args]
(let [my-addresses (:my-addresses db)
{:keys [:contribution-args :address-index]} (s/conform (s/cat :contribution-args (s/? map?)
:address-index (s/? number?))
args)]
(.clear js/console)
{:dispatch [:district0x/clear-smart-contracts]
:async-flow {:first-dispatch [:district0x/load-smart-contracts {:version constants/contracts-version}]
:rules [{:when :seen?
:events [:district0x/smart-contracts-loaded]
:dispatch [:deploy-contribution-contract
(merge
(when (<= 10 (count my-addresses))
#_{:contribution/founder1 (first my-addresses)
:contribution/founder2 (second my-addresses)
:contribution/early-sponsor (first my-addresses)
:contribution/wallet (nth my-addresses 3)
:contribution/advisers (drop 4 (take 7 my-addresses))}
{:contribution/founder1 (first my-addresses)
:contribution/founder2 (first my-addresses)
:contribution/early-sponsor (first my-addresses)
:contribution/wallet (first my-addresses)
:contribution/advisers (repeat 3 (first my-addresses))})
contribution-args)
address-index]}
{:when :seen?
:events [:contribution-contract-deployed]
:dispatch [:deploy-mini-me-token-factory-contract address-index]}
{:when :seen?
:events [:mini-me-token-factory-deployed]
:dispatch [:deploy-dnt-token-contract address-index]}
{:when :seen?
:events [:dnt-token-contract-deployed]
:dispatch [:contribution/set-district0x-network-token address-index]
:halt? true}]}})))
(reg-event-fx
:generate-db
interceptors
(fn [{:keys [:db]}]
{:async-flow
{:first-dispatch [:reinitialize]
:rules [{:when :seen?
:events [:contribution/district0x-network-token-was-set]
:dispatch [:contribution/set-contrib-period
{:contrib-period/start-time (time-coerce/to-epoch (t/plus (t/now) (t/seconds 5)))
:contrib-period/end-time (time-coerce/to-epoch (t/plus (t/now) (t/hours 2)))
:contrib-period/soft-cap-amount (u/eth->wei 5)
:contrib-period/hard-cap-amount (u/eth->wei 100)
:contrib-period/after-soft-cap-duration (t/in-seconds (t/minutes 30))}]}
{:when :seen?
:events [:contribution/contrib-period-was-set]
;:dispatch [:contribution/enable-contrib-period {} (nth (:my-addresses db) 3)]
:dispatch [:contribution/enable-contrib-period {} (first (:my-addresses db))]
:halt? true}]}}))
(reg-event-fx
:compensate-community-advisor
interceptors
(fn [{:keys [db]} [i]]
(when (< i (count constants/community-advisors))
(let [[receiver amount] (nth constants/community-advisors i)]
(println "Sending" amount "DNT to" receiver i)
{:dispatch [:dnt-token/transfer {:dnt-token/to receiver
:dnt-token/value (web3/to-wei amount :ether)}]
:dispatch-later [{:ms 1000 :dispatch [:compensate-community-advisor (inc i)]}]}))))
(reg-event-fx
:community-advisor-balances
interceptors
(fn [{:keys [db]}]
{:web3-fx.blockchain/balances
{:web3 (:web3 db)
:addresses (map first (take 270 constants/community-advisors))
:instance (get-instance db :dnt-token)
:dispatches [[:community-advisor-balances-loaded]
[:district0x/blockchain-connection-error :community-advisor-balances]]}}))
(reg-event-fx
:community-advisor-balances-loaded
interceptors
(fn [{:keys [db]} [balance address]]
(let [balance (bn/->number (web3/from-wei balance :ether))
expected-balance (constants/community-advisors-hashmap address)]
(when (not= balance expected-balance)
(console :log address balance expected-balance)))
nil))
(defn compensate-community-advisor [i stop-at]
(when (< i (min stop-at (count constants/community-advisors-hashmap)))
(let [address (nth (keys constants/community-advisors-hashmap) i)]
(go
(let [[result ch] (alts! [(web3-eth-async/contract-call
(get-instance @re-frame.db/app-db :dnt-token)
:Transfer
{:_from "0x2a2A57a98a07D3CA5a46A0e1d51dEFffBeF54E4F"
:_to address}
{:from-block 0})
(timeout 1000)])]
(if result
(do
(println address "was compensated" i)
(compensate-community-advisor (inc i) stop-at))
(let [amount (constants/community-advisors-hashmap address)]
(println "Sending" amount "to" address i)
(close! ch)
(let [[err res] (wei 5)
:contrib-period/hard-cap-amount (u/eth->wei 10)
:contrib-period/after-soft-cap-duration (t/in-seconds (t/hours 48))}])
(dispatch [:contribution/set-contrib-period
{:contrib-period/start-time (time-coerce/to-epoch (t/plus (t/now) (t/hours 1)))
:contrib-period/end-time (time-coerce/to-epoch (t/plus (t/now) (t/hours 2)))
:contrib-period/soft-cap-amount (u/eth->wei 55000)
:contrib-period/after-soft-cap-duration (t/in-seconds (t/minutes 30))
:contrib-period/hard-cap-amount (u/eth->wei 65000)}
0])
(dispatch [:contribution/set-contrib-period
{:contrib-period/start-time (time-coerce/to-epoch (t/plus (t/now) (t/seconds 30)))
:contrib-period/end-time (time-coerce/to-epoch (t/plus (t/now) (t/hours 2)))
:contrib-period/soft-cap-amount (u/eth->wei 5)
:contrib-period/after-soft-cap-duration (t/in-seconds (t/minutes 10))
:contrib-period/hard-cap-amount (u/eth->wei 10)}
0])
(dispatch [:contribution/set-contrib-period
{:contrib-period/start-time (cljs-time.coerce/to-epoch (cljs-time.core/date-time 2017 7 18 15))
:contrib-period/end-time (cljs-time.coerce/to-epoch (t/plus (cljs-time.core/date-time 2017 7 18 15)
(t/weeks 2)))
:contrib-period/soft-cap-amount (u/eth->wei 58550)
:contrib-period/after-soft-cap-duration (t/in-seconds (t/days 2))
:contrib-period/hard-cap-amount (u/eth->wei 292750)}])
(dispatch [:district0x.contract/constant-fn-call :token-vesting :beneficiary])
(dispatch [:district0x.contract/constant-fn-call :token-vesting :start])
(dispatch [:district0x.contract/constant-fn-call :token-vesting :cliff])
(dispatch [:district0x.contract/constant-fn-call :token-vesting :duration])
(dispatch [:district0x.contract/constant-fn-call :token-vesting :revocable])
(dispatch [:district0x.contract/constant-fn-call :token-vesting :owner])
(dispatch [:district0x.contract/constant-fn-call :multisig-wallet :get-transaction-count true false])
(dispatch [:district0x.contract/constant-fn-call :multisig-wallet :get-transaction-ids 0 9999 true false])
(dispatch [:district0x.contract/constant-fn-call :contribution :district0x-network-token])
(dispatch [:district0x.contract/constant-fn-call :contribution :founder1])
(dispatch [:district0x.contract/constant-fn-call :dnt-token :controller])
(dispatch [:district0x.contract/constant-fn-call :dnt-token :token-grants-count (:contribution/founder1 @re-frame.db/app-db)])
(dispatch [:district0x.contract/constant-fn-call :dnt-token :token-grant (:contribution/founder1 @re-frame.db/app-db) 1])
(dispatch [:district0x.contract/constant-fn-call :contribution :get-running-contrib-period])
(dispatch [:district0x.contract/constant-fn-call :contribution :get-times])
(dispatch [:district0x.contract/constant-fn-call :contribution :get-uncompensated-contributors 0 0])
(dispatch [:contribution/enable-contrib-period {}
(last (:my-addresses @re-frame.db/app-db))])
)
================================================
FILE: src/cljs/contribution/styles.cljs
================================================
(ns contribution.styles
(:require [cljs-react-material-ui.core :refer [color get-mui-theme]]))
(def theme-cyan "#7cf8fa")
(def theme-blue "#2c398f")
(def theme-green "#23fdd8")
(def theme-orange "#ffd500")
(def theme-gray "#47608e")
(def primary1-color theme-cyan)
(def accent1-color theme-cyan)
(def text-color "rgba(0, 0, 0, 0.87)")
(def fade-white-color "rgba(255, 255, 255, 0.8)")
(def fade-white-text
{:color fade-white-color})
(def palette {:primary1-color primary1-color
:accent1-color accent1-color
:text-color "#FFF"})
(def mui-theme (get-mui-theme {:palette palette
:font-family "proxima-soft, sans-serif"
:text-field {:error-color theme-orange
:floating-label-color "#FFF"
:focus-color theme-green
:disabled-text-color "rgba(255, 255, 255, 0.6)"}
:paper {:background-color theme-blue
:color "#FFF"}
:raised-button {:primary-text-color theme-blue
:primary-color theme-green
:disabled-text-color theme-blue
:disabled-color "rgba(255, 255, 255, 0.6)"}
:drop-down-menu {:accent-color theme-blue}
:menu-item {:selected-text-color theme-cyan}
:snackbar {:background-color "rgba(0, 0, 0, 0.95)"
:text-color theme-cyan}}))
;; --- GENERIC STYLES BEGNINNING ---
(def desktop-gutter (aget mui-theme "spacing" "desktopGutter"))
(def desktop-gutter-more (aget mui-theme "spacing" "desktopGutterMore"))
(def desktop-gutter-less (aget mui-theme "spacing" "desktopGutterLess"))
(def desktop-gutter-mini (aget mui-theme "spacing" "desktopGutterMini"))
(def margin-bottom-gutter
{:margin-bottom desktop-gutter})
(def margin-bottom-gutter-more
{:margin-bottom desktop-gutter-more})
(def margin-top-gutter-more
{:margin-top desktop-gutter-more})
(def margin-bottom-gutter-less
{:margin-bottom desktop-gutter-less})
(def margin-bottom-gutter-mini
{:margin-bottom desktop-gutter-mini})
(def margin-top-gutter
{:margin-top desktop-gutter})
(def margin-top-gutter-less
{:margin-top desktop-gutter-less})
(defn margin-all [x]
{:margin-top x
:margin-bottom x
:margin-right x
:margin-left x})
(defn margin-horizontal [x]
{:margin-right x
:margin-left x})
(defn margin-vertical [x]
{:margin-top x
:margin-bottom x})
(defn padding-all [x]
{:padding-top x
:padding-bottom x
:padding-right x
:padding-left x})
(defn padding-horizontal [x]
{:padding-right x
:padding-left x})
(defn padding-vertical [x]
{:padding-top x
:padding-bottom x})
(def text-left
{:text-align :left})
(def text-right
{:text-align :right})
(def text-center
{:text-align :center})
(def full-width
{:width "100%"})
(def full-height
{:height "100%"})
(def no-wrap
{:white-space :nowrap})
(def word-wrap-break
{:word-wrap :break-word})
(def clickable
{:cursor :pointer})
(def display-inline
{:display :inline})
(def display-block
{:display :block})
(def italic-text
{:font-style :italic})
(def bold-text
{:font-style :bold})
;; --- GENERIC STYLES END ---
(def paper
{:border-radius "10px"})
(def content-wrap
(padding-all desktop-gutter))
(def white-text
{:color (color :white)})
(def app-bar
{:background-color "#FFF"
:box-shadow "none"})
(def active-address-select-field
{:color theme-blue
:margin-right 10})
(def active-address-single
{:margin-right 10
:font-size "1.3em"
:line-height "50px"
:color theme-blue})
(def active-address-select-field-label
{:color theme-blue})
(def app-bar-balance
{:color theme-blue})
(def stats-tile-border-right
{:border-right "0.5px solid rgba(255, 255, 255, 0.1)"})
(def stats-tile-border-bottom
{:border-bottom "0.5px solid rgba(255, 255, 255, 0.1)"})
(def stats-tile-border-top
{:border-top "0.5px solid rgba(255, 255, 255, 0.1)"})
(def stats-tile
{:text-align "center"
:height 250
:color theme-green
:font-family "filson-soft, sans-serif"})
(def stats-tile-title
{:text-transform "uppercase"
:font-size "0.95em"
:font-weight "bold"
:padding-bottom desktop-gutter-less
:margin-bottom desktop-gutter-less
:margin-left desktop-gutter-less
:margin-right desktop-gutter-less})
(def contrib-countdown-unit
{:font-size "0.9em"
:width 60
:display :inline-block
:text-align :left})
(def contrib-countdown-value
{:display :inline-block
:font-size "2.7em"
:width 57})
(def logo
{:height 45
:width "auto"
:margin-top 13})
(def stats-tile-amount
{:width "100%"
:font-size "3em"
:display :inline})
(def stats-tile-amount-subtitle
{:width "100%"
:font-size "1.2em"})
(def cap-progress
(merge
margin-bottom-gutter-less
{:height "10px"
:border-radius "10px"}))
(def distribution-note
(merge full-width
fade-white-text
margin-top-gutter
fade-white-text
{:font-size "0.9em"}))
(def contrib-terms-link
{:background-color theme-cyan
:padding "8px 13px"
:font-size "0.75em"
:border-radius "20px"
:color theme-blue
:font-weight "bold"})
(def blob1
{:position :absolute
:top 200
:left "-40%"
:z-index -1
:height 980
:margin-bottom 40})
(def blob2
{:position :absolute
:top 300
:right "-30%"
:z-index -1
:height 800
:overflow :hidden})
(def blob3
{:position :absolute
:right "14%"
:z-index -1
:height 250
:top 1030
:margin-bottom 40})
(def blob4
{:position :absolute
:right "3%"
:z-index -1
:height 60
:top 150})
================================================
FILE: src/cljs/contribution/subs.cljs
================================================
(ns contribution.subs
(:require
[cljs-time.core :as t]
[cljs-web3.core :as web3]
[contribution.constants :as constants]
[district0x.utils :as u]
[goog.string :as gstring]
[goog.string.format]
[medley.core :as medley]
[re-frame.core :refer [reg-sub]]
[clojure.set :as set]
[clojure.string :as string]))
(reg-sub
:db/now
(fn [db]
(:now db)))
(reg-sub
:contribution/dnt-balance
:<- [:district0x/balances]
:<- [:district0x/smart-contracts]
(fn [[balances contracts]]
(get-in balances [(:address (:contribution contracts)) :dnt])))
(reg-sub
:confirmed-not-us-citizen?
(fn [db]
(:confirmed-not-us-citizen? db)))
(reg-sub
:confirmed-terms?
(fn [db]
(:confirmed-terms? db)))
(reg-sub
:confirmations-submitted?
(fn [db]
(:confirmations-submitted? db)))
(reg-sub
:confirmed-gas-price?
(fn [db]
(:confirmed-gas-price? db)))
(reg-sub
:confirmed-compensation?
(fn [db]
(:confirmed-compensation? db)))
(reg-sub
:contribution/contrib-period
(fn [db]
(:contribution/contrib-period db)))
(reg-sub
:disallowed-country?
(fn [db]
(:disallowed-country? db)))
(reg-sub
:admin-addresses
(fn [db]
(:admin-addresses db)))
(reg-sub
:contribution/current-contrib-period-status
:<- [:contribution/contrib-period]
:<- [:db/now]
(fn [[{:keys [:contrib-period/start-time :contrib-period/end-time]} now]]
(cond
(or (not start-time)
(not end-time)
(not (t/before? start-time now)))
:contrib-period-status/not-started
(and (t/after? now start-time)
(t/before? now end-time))
:contrib-period-status/running
(t/after? now end-time)
:contrib-period-status/ended)))
(reg-sub
:contribution/configuration
(fn [db]
(merge
(select-keys db [:contribution/stopped? :contribution/founder1 :contribution/founder2
:contribution/early-sponsor :contribution/wallet :contribution/advisers
:contribution/max-gas-price])
{:contribution-address (get-in db [:smart-contracts :contribution :address])
:dnt-token-address (get-in db [:smart-contracts :dnt-token :address])})))
(reg-sub
:contribution-contract-address
:<- [:district0x/smart-contracts]
(fn [contracts]
(get-in contracts [:contribution :address])))
(reg-sub
:db/can-see-admin-panel?
:<- [:district0x/my-addresses]
:<- [:admin-addresses]
(fn [[my-addresses admin-addresses]]
(boolean (seq (set/intersection (set (map string/lower-case my-addresses))
(set (map string/lower-case admin-addresses)))))))
(reg-sub
:form.contribution/enable-contrib-period
(fn [db _]
(:default (:form.contribution/enable-contrib-period db))))
(reg-sub
:form.contribution/contribute
(fn [db _]
(:default (:form.contribution/contribute db))))
================================================
FILE: test/contribution/cmd.cljs
================================================
(ns contribution.cmd
(:require
[cljs.nodejs :as nodejs]
[contribution.tests]
[cljs.test :refer-macros [run-tests]]
#_[doo.runner :refer-macros [doo-tests]]))
(nodejs/enable-util-print!)
(set! js/window #js {})
#_(doo-tests 'contribution.tests)
(set! (.-error js/console) (fn [x] (.log js/console x)))
(comment
(run-all-tests)
(run-tests 'contribution.tests)
((doo-tests 'contribution.tests)))
(defn -main [& _]
(run-tests 'contribution.tests))
(set! *main-cli-fn* -main)
================================================
FILE: test/contribution/tests.cljs
================================================
(ns contribution.tests
(:require
[cljs-time.coerce :refer [to-epoch]]
[cljs-time.core :as time]
[cljs-web3.core :as web3]
[cljs-web3.eth :as web3-eth :refer [contract-call]]
[cljs-web3.evm :as web3-evm]
[cljs.core.async :refer [! chan]]
[cljs.nodejs :as nodejs]
[cljs.test :refer-macros [deftest is testing run-tests use-fixtures async]]
[contribution.api :refer [parse-get-contrib-period contrib-period-args parse-get-configuration]]
[district0x.big-number :as bn]
[district0x.test.contracts :as test-utils :refer [state-call! now-plus-seconds get-balance-ch contract-call-ch state-call-ch! state-call-ch! increase-time-and-mine-ch! mine-ch!]]
[district0x.test.node :refer [fetch-contract fetch-bin fetch-abi]]
[district0x.utils :as u :refer [wei->eth->num eth->wei->num]]
[print.foo :include-macros true])
(:require-macros [cljs.core.async.macros :refer [go]]))
(def accounts-secrets ["0x2331c9b2390ff4acfd9bb1277f35cb303581bf8d30433aec9d517dd7c6213e05"
"0x862b9e4ac273b75153122c16611bb73b85ee35d2443f49b6651dde9b624d3175"
"0xfe7a2920e0b7572ee98e78b4a551723697c1678bed60d2c7ddd8d015ea15f241"
"0x84aae7d13483fc0ef0910cae872a15a10f60a495b7067793bc868250d1c760ba"
"0x4919c9259eac34d6af231edf36af697f7a6291bc28c9837f7fabb678e750fb98"
"0xbad6bfea21ca0d5d9e02f8a6854a5d6aea31fc57505ce336ea7ebbf31e91f487"
"0xd804f2fe99d8186aa9dc2a6e74c0c4a551b12d29db9bba79187664b86a830659"
"0x564af4b4727963fd3830abfdef5f97ba2b06926760aaff5869e6f8f4ce6e2538"
"0x5a157c8984c783fe9e1fc33f8b25e5a2b9d46b78b06e8d0081d594483fb52a52"
"0xe80a3596cd9c6daaa66007e742d5fc07a7cb0d139f2a904a218edb14d47e7de2"
"0x7bb136a6ec7bbe915bf8acc42ce0625936c5ddf970c23953b81f5304ace40c08"
"0xc65d6da272a181baa120e492e69bb94a4cfc70188fbe97cd46359c0f35a78f92"
"0x433fdca0953ec0b358178085e74d108587374f4d8b823cf93e3c46685981b6a6"
"0x99465e2dc764d25d60f76c0f3f7857bfacd873c8958cc24bf5361e1f57abc1ea"
"0xbd410cd7cfe6209e37b37ca3dd316b63971633a7e3a6c4781137df35fae5c23a"])
(def accounts ["0x76852ba1f2fcb6355c57ffbd0bccfc226411f611"
"0xe5e0c25e7928ddb94a5a9569e25bdb1c5ef68392"
"0x7d3a19dc294eb5043e019b72adae56d67eaa4b07"
"0xd43c63869ea4c4a73efe218321a4f0653304026f"
"0xb2165ba402f5625ba5d59bc432b79bcc342250ae"
"0x979582a341f47a4caeac6cefb1a3af123a939264"
"0xb66b622f6ee6cc98581ed03ea2a393cb2de7a33e"
"0x6e17baf999bb6a6204d80d55a3e0910e7d4eceed"
"0x85ebe786470fd4204b307f39f49724136fcd2a2c"
"0x46f9d973f77133ecbfc0d1f43de3c00147a82096"
"0x0cf38f282e4cd051ca637115f745a8f60cbd215e"
"0xebbf7c3882b86f5eb4f13dbaed2487837f6ce786"
"0x4ee964fa20f7f3195b34a2d76579ced86a3de171"
"0xdd88343d4760e872d86a309c6cd3a4ed247fd335"
"0x1a1191cea03f9a15159f77e5e50f221c2b4b7eff"])
(def Web3 (js/require "web3"))
(def TestRPC (js/require "ethereumjs-testrpc"))
(set! js/Web3 Web3)
(def web3 (new Web3))
(def ^:dynamic MiniMeTokenFactory nil)
(def ^:dynamic Contribution nil)
(def ^:dynamic DNTToken nil)
(def owner1 (nth accounts 0))
(def wallet (nth accounts 10))
(def founder1 (nth accounts 2))
(def founder2 (nth accounts 3))
(def early-sponsor (nth accounts 4))
(def adviser1 (nth accounts 5))
(def adviser2 (nth accounts 6))
(def adviser3 (nth accounts 7))
(def adviser4 (nth accounts 8))
(def community-advisors (nth accounts 9))
(defn- get-dnt-balance [address]
(contract-call-ch (chan 1 (map wei->eth->num)) DNTToken :balance-of address))
(defn- contrib-period-running? []
(contract-call-ch Contribution :is-contrib-period-running))
(defn get-contrib-period []
(contract-call-ch (chan 1 (map parse-get-contrib-period)) Contribution :get-contrib-period))
(defn deploy-contracts! [done]
(go
(.setProvider web3 (.provider TestRPC (clj->js {:accounts (->> accounts-secrets
(map (fn [secret]
{:balance (web3/to-wei 0x64 :ether)
:secretKey secret})))
:locked false})))
(set! MiniMeTokenFactory (eth->num (wei->num 10)
after-soft-cap-duration (time/in-seconds (time/hours 48))
hard-cap-amount (eth->wei->num 15)
start-time-seconds 60
end-time-seconds 120
start-time (now-plus-seconds start-time-seconds)
end-time (now-plus-seconds end-time-seconds)]
(testing "Should be able to set contribution period"
(is (u/sha3? (eth->num soft-cap-amount) (:contrib-period/soft-cap-amount contrib-period)))
(is (= after-soft-cap-duration (:contrib-period/after-soft-cap-duration contrib-period)))
(is (= start-time (to-epoch (:contrib-period/start-time contrib-period))))
(is (= end-time (to-epoch (:contrib-period/end-time contrib-period))))
(is (= false (:contrib-period/enabled? contrib-period)))
(is (= false (:contrib-period/soft-cap-reached? contrib-period)))
(is (zero? (:contrib-period/total-contributed contrib-period)))
(is (zero? (:contrib-period/contributors-count contrib-period))))
(is (= 119000000 (eth->num soft-cap-amount) (:contrib-period/soft-cap-amount contrib-period)))
(is (= after-soft-cap-duration (:contrib-period/after-soft-cap-duration contrib-period)))
(is (= start-time (to-epoch (:contrib-period/start-time contrib-period))))
(is (= end-time (to-epoch (:contrib-period/end-time contrib-period))))
(is (= false (:contrib-period/enabled? contrib-period)))
(is (= false (:contrib-period/soft-cap-reached? contrib-period)))
(is (zero? (:contrib-period/total-contributed contrib-period)))
(is (zero? (:contrib-period/contributors-count contrib-period))))
(is (= 119000000 (> contributions
(map second)
(reduce + 0)
eth->wei->num)
expected-dnt-balances [(web3/to-big-number "85714285714285714285714285")
(web3/to-big-number "128571428571428571428571427")
(web3/to-big-number "171428571428571428571428570")
(web3/to-big-number "214285714285714285714285712")]
dnt-compensated-total (reduce bn/+ (web3/to-big-number 0) expected-dnt-balances)]
(testing "Users should be able to contribute"
(doseq [[contributor amount] contributions]
(is (u/sha3? (eth->num contrib-amount) amount))
(is (false? compensated?))))
(let [contrib-period (eth->num contribs-total) (:contrib-period/total-contributed contrib-period)))
(is (= (count contributors) (:contrib-period/contributors-count contrib-period)))))
(testing "Shouldn't be able to compensate when contrib period is still running"
(is (u/error? (eth->num dnt-compensated-total))))))))
(done))))
(deftest contribution2
(async done
(go
(let [soft-cap-amount (eth->wei->num 3)
hard-cap-amount (eth->wei->num 6)
start-time-seconds 300
after-soft-cap-seconds 200
start-time (now-plus-seconds start-time-seconds)
end-time (now-plus-seconds 10000)
contributions [[(nth accounts 13) 2] [(nth accounts 14) 2]]
contributors (mapv first contributions)
contribs-total (->> contributions
(map second)
(reduce + 0)
eth->wei->num)
expected-dnt-balances [(bn/+ (eth->num soft-cap-amount) (:contrib-period/soft-cap-amount contrib-period)))
(is (= after-soft-cap-seconds (:contrib-period/after-soft-cap-duration contrib-period)))
(is (= start-time (to-epoch (:contrib-period/start-time contrib-period))))
(is (= end-time (to-epoch (:contrib-period/end-time contrib-period))))
(is (= false (:contrib-period/enabled? contrib-period)))
(is (= false (:contrib-period/soft-cap-reached? contrib-period)))
(is (zero? (:contrib-period/total-contributed contrib-period)))
(is (zero? (:contrib-period/contributors-count contrib-period))))
(is (u/sha3? (eth->num contrib-amount) amount))
(is (false? compensated?))))
(testing "Hitting soft cap should change contrib period end time"
(let [contrib-period (eth->num contribs-total) (:contrib-period/total-contributed contrib-period)))
(is (= (count contributors) (:contrib-period/contributors-count contrib-period)))))
(wei->num 1)
after-soft-cap-duration (time/in-seconds (time/hours 48))
hard-cap-amount (eth->wei->num 2)
now (bn/->number (eth->num contrib-amount) 1))
(is (false? compensated?))))
(testing "After hitting hard cap users shouldn't be able to contribute"
(doseq [[contributor amount] (drop 2 contributions)]
(is (u/error? (wei->num 1)]})))))
(testing "Should be able to enable dnt token transfers"
(is (u/sha3? (wei->num 1)]}))))
(is (= 1 (wei->eth->num (bn/->number (wei->num 1)]})))))
(testing "Community advisors stake should not be vested"
(is (u/sha3? (wei->num 1)]})))))
(testing "Other addresses besides contribution contract can't create vesting"
(is (u/error? (wei->num 1)
(+ now 120)
(+ now 180)
(+ now 300)
false
false]})))))
(testing "Funds should not be vested after vesting period"
(wei->num 1)]})))))
(testing "Contribution Contract can be killed"
(is (u/sha3? (