├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── config
└── default.json
├── custom_typings
├── system.d.ts
├── web3.d.ts
└── web3_global.d.ts
├── docs
├── Configuration.md
├── Daos.md
├── DeveloperDocs.md
├── Events.md
├── GanacheDb.md
├── Proposals.md
├── README.md
├── Scripts.md
├── Transactions.md
├── Wrappers.md
├── index.html
└── index.md
├── lib
├── accountService.ts
├── avatarService.ts
├── commonTypes.ts
├── configService.ts
├── contractWrapperBase.ts
├── contractWrapperFactory.ts
├── controllerService.ts
├── dao.ts
├── iConfigService.ts
├── iContractWrapperBase.ts
├── index.ts
├── loggingService.ts
├── promiseEventService.ts
├── proposalGeneratorBase.ts
├── proposalService.ts
├── pubSubEventService.ts
├── schemeWrapperBase.ts
├── scripts
│ └── createGenesisDao.ts
├── test
│ └── wrappers
│ │ └── testWrapper.ts
├── transactionService.ts
├── uSchemeWrapperBase.ts
├── utils.ts
├── utilsInternal.ts
├── web3EventService.ts
├── wrapperService.ts
└── wrappers
│ ├── absoluteVote.ts
│ ├── auction4Reputation.ts
│ ├── commonEventInterfaces.ts
│ ├── contributionReward.ts
│ ├── daoCreator.ts
│ ├── daoToken.ts
│ ├── externalLocking4Reputation.ts
│ ├── fixedReputationAllocation.ts
│ ├── genesisProtocol.ts
│ ├── globalConstraintRegistrar.ts
│ ├── iBurnableToken.ts
│ ├── iErc827Token.ts
│ ├── iIntVoteInterface.ts
│ ├── intVoteInterface.ts
│ ├── locking4Reputation.ts
│ ├── lockingEth4Reputation.ts
│ ├── lockingToken4Reputation.ts
│ ├── mintableToken.ts
│ ├── redeemer.ts
│ ├── reputation.ts
│ ├── schemeRegistrar.ts
│ ├── standardToken.ts
│ ├── tokenCapGC.ts
│ ├── upgradeScheme.ts
│ ├── vestingScheme.ts
│ └── voteInOrganizationScheme.ts
├── mkdocs.yml
├── package-lock.json
├── package-scripts.js
├── package-scripts
├── archiveGanacheDb.js
├── cleanMigrationJson.js
├── createApiPagesList.js
├── createGenesisDao.js
├── fail.js
├── migrateContracts.js
├── recursiveCopy.js
├── typedoc.js
└── unArchiveGanacheDb.js
├── package.json
├── test
├── absoluteVote.ts
├── accountService.ts
├── config.ts
├── contributionReward.ts
├── dao.ts
├── daoCreator.ts
├── estimateGas.ts
├── genesisProtocol.ts
├── globalConstraintRegistrar.ts
├── helpers.ts
├── redeemer.ts
├── schemeRegistrar.ts
├── tokens.ts
├── transactionService.ts
├── tsconfig.json
├── upgradeScheme.ts
├── utils.ts
├── vestingScheme.ts
├── voteInOrganizationScheme.ts
├── web3EventService.ts
└── wrapperService.ts
├── truffle.js
├── tsconfig.json
└── tslint.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .node-xmlhttprequest-sync*
3 | .node-xmlhttprequest-content*
4 | *.tgz
5 | .vscode/
6 | ganacheDb/
7 | dist/
8 | ganacheDb.zip
9 | migrated_contracts/
10 | *.sublime-project
11 | yarn.lock
12 | test-build/
13 | site/
14 | docs/api/
15 | .vs/
16 | migration.json
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 |
3 | language: node_js
4 |
5 | node_js:
6 | - "9.3.0"
7 |
8 | before_install:
9 | - sudo apt-get update -qq
10 | - sudo apt-get install software-properties-common -y -qq
11 | - sudo add-apt-repository -y ppa:ethereum/ethereum
12 | - sudo add-apt-repository -y ppa:ethereum/ethereum-dev
13 | - sudo apt-get update -qq
14 | - sudo apt-get install geth -y -qq
15 |
16 | install:
17 | - npm install
18 | - nohup npm start ganache &
19 | - npm start migrateContracts.fetchContracts
20 | - npm start migrateContracts
21 |
22 | script:
23 | - npm start lint
24 | - npm start test
25 |
26 | notifications:
27 | slack: daostack:fGuaFPsiQiV5mgmzRcSzbYqw
28 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribution Guide
2 | ___
3 |
4 | Firstly, thanks for wanting to help with the development of DAOSTACK. All contributions, code or documents, should come from a forked version of the respective repository. Then the proposed changes must be submitted via a pull request to the master branch. All pull requests must be reviewed by the maintainers of the repository in question. Once a pull request has been reviewed & approved; you should merge and rebase, and then delete the branch.
5 | GitHub [keywords](https://help.github.com/articles/closing-issues-using-keywords/) should be used when closing pull requests and issues.
6 |
7 | If you wish to submit more substantial changes or additions, please see the feature contributions section below.
8 |
9 |
10 | ## Git Practice
11 |
12 | Branches should be named with a brief semantic title.
13 | Commit messages should be capitalised and follow these rules:
14 | ```
15 | Short (50 chars or less) summary of changes
16 |
17 | More detailed explanatory text, if necessary. Wrap it to about 72
18 | characters or so. In some contexts, the first line is treated as the
19 | subject of an email and the rest of the text as the body. The blank
20 | line separating the summary from the body is critical (unless you omit
21 | the body entirely); tools like rebase can get confused if you run the
22 | two together.
23 |
24 | Further paragraphs come after blank lines.
25 |
26 | - Bullet points are okay, too
27 |
28 | - Typically a hyphen or asterisk is used for the bullet, preceded by a
29 | single space, with blank lines in between, but conventions vary here
30 |
31 | Issue: #1, #2
32 | ```
33 | A properly formed Git commit subject line should always be able to complete the following sentence:
34 |
35 | If applied, this commit will _Your subject line here_
36 |
37 | **Please refer to [this guide](https://chris.beams.io/posts/git-commit/) for additional information.**
38 |
39 |
40 | ## Feature Contributions
41 |
42 | For the submission of more substantial changes or additions, an issue should be opened outlining what is being proposed for implementation. The title of the issue should be descriptive and brief, follow the same rules as a commit message, as outlined above. The body of the issue should detail the reasoning for the need of the work to be carried out and the desired outcome.
43 |
44 |
45 | ## Code Formatting and Commentary
46 |
47 | ### JavaScript
48 | All JavaScript must be formatted with [ESLint](https://eslint.org/) using the DAOSTACK [configuration](https://github.com/daostack/arc.js/blob/master/.eslintrc.json).
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/daostack/arc.js)
2 | [](https://www.npmjs.org/package/@daostack/arc.js)
3 |
4 | # DAOstack Arc.js
5 |
6 | [DAOstack Arc.js](https://github.com/daostack/arc.js) sits just above [DAOstack Arc](https://github.com/daostack/arc) on the DAO stack. It is a library that facilitates javascript application access to the DAOstack Arc ethereum smart contracts.
7 |
8 | For more information about Arc contracts and the entire DAOstack ecosystem, please refer to the [Arc documentation](https://daostack.github.io/arc/README/).
9 |
10 | ### Documentation
11 | Check out the [complete documentation on Arc.js](https://daostack.github.io/arc.js).
12 |
13 | ## Contribute to Arc.js
14 |
15 | PRs are welcome but please first consult with the [Contribution guide](https://github.com/daostack/arc/blob/master/CONTRIBUTING.md).
16 |
17 | Refer to the [Arc.js Developer Documentation](docs/DeveloperDocs.md).
18 |
19 | Join us on [Slack](https://daostack.slack.com/)!
20 |
21 | Join us on [Telegram](https://t.me/daostackcommunity)!
22 |
23 | ## Security
24 | DAOstack Arc.js is still on its alpha version. It is meant to provide secure, tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problem you might experience.
25 |
26 | ## License
27 | This is an open source project ([GPL license](https://github.com/daostack/arc.js/blob/master/LICENSE)).
28 |
--------------------------------------------------------------------------------
/config/default.json:
--------------------------------------------------------------------------------
1 | {
2 | "autoApproveTokenTransfers": true,
3 | "defaultVotingMachine": "AbsoluteVote",
4 | "cacheContractWrappers": true,
5 | "logLevel": 9,
6 | "estimateGas": false,
7 | "defaultGasLimit": 4543760,
8 | "gasPriceAdjustor": null,
9 | "txDepthRequiredForConfirmation": {
10 | "default": 7,
11 | "ganache": 0,
12 | "live": 20
13 | },
14 | "providerPort": 8545,
15 | "providerUrl": "127.0.0.1",
16 | "networkDefaults": {
17 | "live": {
18 | "host": "127.0.0.1",
19 | "port": 8546
20 | },
21 | "private": {
22 | "host": "127.0.0.1",
23 | "port": 8545
24 | },
25 | "ganache": {
26 | "host": "127.0.0.1",
27 | "port": 8545
28 | },
29 | "ropsten": {
30 | "host": "127.0.0.1",
31 | "port": 8548
32 | },
33 | "kovan": {
34 | "host": "127.0.0.1",
35 | "port": 8547
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/custom_typings/system.d.ts:
--------------------------------------------------------------------------------
1 | declare module "system" {
2 | global {
3 | var window: Window;
4 | var artifacts: any;
5 | }
6 | }
7 |
8 | declare module "*.json" {
9 | const value: any;
10 | export default value;
11 | }
12 |
--------------------------------------------------------------------------------
/custom_typings/web3_global.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable-next-line:no-reference */
2 | ///
3 | declare module "web3" {
4 | global {
5 | let web3: Web3;
6 | let accounts: Array;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/DeveloperDocs.md:
--------------------------------------------------------------------------------
1 | # Arc.js Architecture Review
2 |
3 | The following is a brief sketch of the primary structures of the code in Arc.js.
4 |
5 | Git repository is [here](https://github.com/daostack/arc.js).
6 |
7 | User documentation is [here](https://daostack.github.io/arc.js).
8 |
9 | Both code and automated tests are written in TypeScript.
10 |
11 | Code standards are enforced by TsLint rules defined in [tslint.json](https://github.com/daostack/arc.js/blob/master/tslint.json).
12 |
13 | User documentation is generated using [TypeDoc](http://typedoc.org/) and [MkDocs](https://www.mkdocs.org/). Typedocs is configured and executed using [typedoc.js](https://github.com/daostack/arc.js/blob/master/package-scripts/typedoc.js). MkDocs is configured in [mkdocs.yml](https://github.com/daostack/arc.js/blob/master/mkdocs.yml).
14 |
15 | While some scripts are available in package.json, all are defined in [package-scripts.js](https://github.com/daostack/arc.js/blob/master/package-scripts.js). Package-script.js leverages [nps](https://github.com/kentcdodds/nps) and defers to several custom javascript node scripts contained [here](https://github.com/daostack/arc.js/tree/master/package-scripts).
16 |
17 | Code is located in the [lib folder](https://github.com/daostack/arc.js/tree/master/lib), tests under [test](https://github.com/daostack/arc.js/tree/master/test).
18 |
19 | Most of the code modules define either an Arc contract wrapper class or a service class.
20 |
21 | Arc contract wrapper classes are all located under [lib/wrappers](https://github.com/daostack/arc.js/tree/master/lib/wrappers).
22 |
23 | Service classes are all located in lib (though there is a [ticket to move them](https://github.com/daostack/arc.js/issues/208))
24 |
25 | More on wrappers and services follows.
26 |
27 | ## Installation
28 |
29 | When you first clone the arc.js repo, run the script:
30 |
31 | ```script
32 | npm install
33 | npm start migrateContracts.fetchContracts
34 | ```
35 |
36 | This will install the Truffle artifact files from Arc and the migration.json file from [DAOstack Migrations](https://github.com/daostack/migration).
37 |
38 |
39 | ## Arc Contract Wrappers
40 | Every Arc contract wrapper class has as its root base the [ContractWrapperBase](https://github.com/daostack/arc.js/blob/master/lib/contractWrapperBase.ts) class.
41 |
42 | Several classes inherit from `ContractWrapperBase`, including:
43 |
44 | * [IntVoteInterfaceWrapper](https://github.com/daostack/arc.js/blob/master/lib/intVoteInterfaceWrapper.ts)
45 | * [SchemeWrapperBase](https://github.com/daostack/arc.js/blob/master/lib/schemeWrapperBase.ts)
46 | * [USchemeWrapperBase](https://github.com/daostack/arc.js/blob/master/lib/uSchemeWrapperBase.ts)
47 | * [ProposalGeneratorBase](https://github.com/daostack/arc.js/blob/master/lib/proposalGeneratorBase.ts)
48 |
49 |
50 | Each wrapper can be instantiated and hydrated using the [ContractWrapperFactory class](https://github.com/daostack/arc.js/blob/master/lib/contractWrapperFactory.ts). The word “hydrated” means to initialize a wrapper instance with information from the chain using `.new`, `.at` or `.deployed`.
51 |
52 | Not all wrapper classes inherit directly from `ContractWrapperBase`. The two voting machine classes inherit from [IntVoteInterfaceWrapper](https://github.com/daostack/arc.js/blob/master/lib/wrappers/intVoteInterface.ts) which in turn inherits from `ContractWrapperBase`.
53 |
54 | ## Other classes
55 |
56 | **[utils.ts](https://github.com/daostack/arc.js/blob/master/lib/utils.ts)** - provides miscellaneous functionality, including initializing `web3`, creating a truffle contract from a truffle contract artifact (json) file, and others.
57 |
58 | **[utilsInternal.ts](https://github.com/daostack/arc.js/blob/master/lib/utilsInternal.ts)** -- internal helper functions not exported to the client.
59 |
60 | **[Dao.ts](https://github.com/daostack/arc.js/blob/master/lib/dao.ts)** -- not a wrapper, nor defined as a service, more like an entity, it provides helper functions for DAOs, particularly `DAO.new` and `DAO.at`.
61 |
62 | ## Arc.js initialization
63 |
64 | Arc.js typings are available to application via [index.ts](https://github.com/daostack/arc.js/blob/master/lib/index.ts).
65 |
66 | At runtime, applications must initialize Arc.js by calling `InitializeArcJs` which is defined in [index.ts](https://github.com/daostack/arc.js/blob/master/lib/index.ts). This might be viewed as the entry-point to Arc.js.
67 |
68 | ## Migrations
69 | Arc.js uses the [DAOstack Migrations](https://github.com/daostack/migration) package to migrate contracts to Ganache, and as a source of Arc contract addresses as migrated to the various networks and to Ganache after running the migration script that Arc.js provides. These addresses are stored in "/migration.json".
70 |
71 | !!! note
72 | As of this writing, the DAOstack Migration package only includes Ganache addresses.
73 |
74 | ## Scripts
75 |
76 |
77 | ### Build
78 |
79 | Build the distributable code like this:
80 |
81 | ```script
82 | npm start build
83 | ```
84 |
85 | Build the test code like this:
86 |
87 | ```script
88 | npm start test.build
89 | ```
90 |
91 | ### Lint
92 |
93 | Run lint on both library and test code like this:
94 |
95 | ```script
96 | npm start lint
97 | ```
98 |
99 | !!! info
100 | The above script runs `npm start lint.code` and `npm start lint.test`
101 |
102 | To lint and fix:
103 |
104 | ```script
105 | npm start lint.andFix
106 | ```
107 |
108 | !!! info
109 | You can also fix code and test separately: `npm start lint.code.andFix` and `npm start lint.test.andFix`
110 |
111 |
112 | ### Tests
113 |
114 | To run the Arc.js tests, run the following script in the Arc.js root folder, assuming you have already run `npm install`, and are running a ganache with migrated Arc contracts (see "Getting Started" in the [Arc.js Documentation](https://daostack.github.io/arc.js)):
115 |
116 | ```script
117 | npm start test
118 | ```
119 |
120 | This script builds all of the code and runs all of the tests.
121 |
122 | !!! info
123 | Both application and test code are written in TypeScript.
124 |
125 | #### Stop tests on the first failure
126 |
127 | ```script
128 | npm start test.bail
129 | ```
130 |
131 | #### Run tests defined in a single test module
132 |
133 | Sometimes you want to run just a single test module:
134 |
135 | ```script
136 | npm start "test.run test-build/test/[filename]"
137 | ```
138 |
139 | To bail:
140 |
141 | ```script
142 | npm start "test.run --bail test-build/test/[filename]"
143 | ```
144 |
145 | Unlike `test`, the script `test.run` does not build the code first, it assumes the code has already been built, which you can do like this:
146 |
147 | ```script
148 | npm start test.build
149 | ```
150 |
151 | ### Build Documentation
152 |
153 | Build the documentation like this:
154 |
155 | ```script
156 | npm start docs.build
157 | ```
158 |
159 | Preview the documentation:
160 |
161 | ```script
162 | npm start docs.build.andPreview
163 | ```
164 |
165 | Publish the documentation:
166 |
167 | ```script
168 | npm start docs.build.andPublish
169 | ```
170 |
--------------------------------------------------------------------------------
/docs/GanacheDb.md:
--------------------------------------------------------------------------------
1 | # Running Arc.js Against a Ganache database
2 |
3 | It can be very handy to run Arc.js tests or your application against a Ganache database that is a snapshot of the chain at any given point. Here's how, assuming you are running the script from your application (which is why you see "`npm explore @daostack/arc.js -- `" prepended to each script command).
4 |
5 | !!! note
6 | These instructions are very similar to those you would use when [_not_ running Ganache against a database](index.md#migratetoganache).
7 |
8 | ### Start Ganache
9 |
10 | First you want to run Ganache with the appropriate flags that will create a database.
11 |
12 | ```script
13 | npm explore @daostack/arc.js -- npm start ganacheDb
14 | ```
15 |
16 | You can use this same command when you a restarting Ganache against a pre-populated database.
17 |
18 | ### Migrate Contracts
19 |
20 | Now migrate the Arc contracts. You only absolutely need to do this when you are starting from scratch with a new database, but you can do it whenever you wish.
21 |
22 | ```script
23 | npm explore @daostack/arc.js -- npm start ganacheDb.migrateContracts
24 | ```
25 |
26 | ### Terminate Ganache
27 | To save the current state so that you can restore it later in cases where the database has become no longer useful, manually, in your own OS, terminate the Ganache process you spawned above.
28 |
29 | ### Zip the Ganache Database
30 | If you want you can zip the database for later reuse when you wish to restore a database to the zipped snapshot.
31 |
32 | ```script
33 | npm explore @daostack/arc.js -- npm start ganacheDb.zip
34 | ```
35 |
36 | At this point you can restart Ganache as above and it will recommence from the point represented in the zipped snapshot.
37 |
38 | ### Restore Ganache Snapshot
39 |
40 | After running against the database you may want to restart Ganache, recommencing at the point at which you [zipped up a snapshot](#zip-the-ganache-database).
41 |
42 | First make sure you have [terminated Ganache](#terminate-ganache), then unzip the database:
43 |
44 | ```script
45 | npm explore @daostack/arc.js -- npm start ganacheDb.restoreFromZip
46 | ```
47 | Now when you restart ganacheDb it will be running against the previously-zipped snapshot.
48 |
49 | ### Start Clean
50 | To start again fully from scratch, an empty database, you can clean out the pre-existing database. Note this can take a long time as there may be thousands of files to delete:
51 |
52 | ```script
53 | npm explore @daostack/arc.js -- npm start ganacheDb.clean
54 | ```
55 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # DAOstack Arc.js Documentation Repository
2 |
3 | **Attention**: Viewing documentation directly in the Arc.js GitHub repository is not supported as a means of obtaining Arc.js documentation online; you will find that not all of the links work and some of the styling doesn't appear the way it is supposed to.
4 |
5 | Much better is the [official Arc.js documentation site](https://daostack.github.io/arc.js).
6 |
7 |
--------------------------------------------------------------------------------
/docs/Scripts.md:
--------------------------------------------------------------------------------
1 | # Running Arc.js Scripts
2 | Arc.js contains a set of scripts for building, publishing, running tests and migrating contracts to any network. These scripts are meant to be accessible to and readily usable by client applications.
3 |
4 | Typically an application that has installed the Arc.js `npm` package will run an Arc.js script by prefixing "`npm explore @daostack/arc.js -- `" to the name Arc.js script command. For example, to run the Arc.js script `npm start ganache` from your application, you would run:
5 |
6 | ```script
7 | npm explore @daostack/arc.js -- npm start ganache
8 | ```
9 |
10 | Otherwise, when running the scripts at the root of an Arc.js repo, you must omit the `npm explore @daostack/arc.js -- ` so it looks like this.
11 |
12 | ```script
13 | npm start ganache
14 | ```
15 |
16 | !!! info "nps"
17 | Other scripts not described here are defined in `package-scripts.js` that is used to configure a tool called [nps](https://www.npmjs.com/package/nps). Arc.js uses `nps` run all of its scripts. While `nps` is installed locally by Arc.js, you can also install it globally and then substitute `npm start` with `nps`, so, when running scripts from the root of an Arc.js repo, it looks like this:
18 |
19 | ```script
20 | nps ganache
21 | ```
22 |
--------------------------------------------------------------------------------
/docs/Wrappers.md:
--------------------------------------------------------------------------------
1 | # Arc Contract Wrappers
2 |
3 | ## Overview
4 |
5 | Arc.js wraps several Arc contracts in a "contract wrapper" JavaScript class. Every wrapper class inherits ultimately from [ContractWrapperBase](/arc.js/api/classes/ContractWrapperBase) providing a common set of functions and properties and specific helper functions for operations specific to the contract it wraps.
6 |
7 | Each wrapper contains some basic properties:
8 |
9 | - `name` - the name of the wrapped Arc contract
10 | - `friendlyName` - a more friendly name of the Arc contract
11 | - `address` - the address of the wrapped Arc contract
12 | - `contract` - the original "wrapped" [Truffle contract](https://github.com/trufflesuite/truffle-contract) that you can use to access all of the Truffle and Web3 functionality of the specific Arc contract being wrapped.
13 | - `factory` - a static instance of a wrapper factory class based on [ContractWrapperFactory<TWrapper>](/arc.js/api/classes/ContractWrapperFactory) (where `TWrapper` is the type (class) of the wrapper). Each factory contains static methods:
14 | - `at(someAddress)`
15 | - `new()`
16 | - `deployed()`
17 |
18 | ... that you can use to instantiate the associated wrapper class.
19 |
20 | ### Events
21 | Each wrapper includes the wrapped contract's events as properties that give you enhanced capabilities over the straight Truffle/Web3 event API. For more information about wrapped contract events, see [Web3 Events](#web3events).
22 |
23 |
24 |
25 | ### Types of Wrappers
26 |
27 | Arc contracts and associated Arc.js contract wrapper classes are categorized as follows:
28 |
29 | **Universal Schemes**
30 |
31 | * ContributionReward
32 | * GlobalConstraintRegistrar
33 | * SchemeRegistrar
34 | * UpgradeScheme
35 | * VestingScheme
36 | * VoteInOrganizationScheme
37 |
38 | **Voting Machines**
39 |
40 | * AbsoluteVote
41 | * GenesisProtocol
42 |
43 | **Global Constraints**
44 |
45 | * TokenCapGC
46 |
47 | **Others**
48 |
49 | * DaoCreator
50 | * Redeemer
51 |
52 | See more at [Enumerate wrappers by contract type](#wrappersByContractType).
53 |
54 | ### Obtaining Wrappers
55 |
56 | Arc.js provides multiple ways to obtain contract wrappers, each optimal for particular use cases. It all starts with the [WrapperService](/arc.js/api/classes/WrapperService) which provides means of organizing and obtaining contract wrappers. The `WrapperService` API is primarily in the form of four static properties, each of which are exported for easy import in your code:
57 |
58 |
59 | Export | WrapperService property | Description
60 | ---------|----------|---------
61 | ContractWrappers | WrapperService.wrappers | Properties are contract names, values are the corresponding contract wrapper
62 | ContractWrapperFactories | WrapperService.factories | Properties are contract names, values are the corresponding contract wrapper factory
63 | ContractWrappersByType | WrapperService.wrappersByType | Properties are a contract category name (see [Contract Types](#contracttypes)), values are an array of `IContractWrapper`
64 | ContractWrappersByAddress | WrapperService.wrappersByAddress | a `Map` where the key is an address and the associated value is a `IContractWrapper` for a contract as deployed by the currently-running version of Arc.js.
65 |
66 | The following sections describe how to obtain wrapper classes in several use cases:
67 |
68 | - [get a deployed wrapper by the Arc contract name](#get-a-deployed-wrapper-by-name)
69 | - [get a wrapper at a given address](#get-a-wrapper-at-a-given-address)
70 | - [deploy a new contract](#deploy-a-new-contract)
71 | - [enumerate all of the deployed wrappers](#enumerate-all-of-the-deployed-wrappers)
72 | - [enumerate wrappers by contract type](#wrappersByContractType)
73 |
74 |
75 | !!! note "Keep in mind"
76 | In Arc.js all token and reputation amounts should always be expressed in Wei, either as a `string` or a `BigNumber`.
77 |
78 |
79 | ## Get a deployed wrapper by Arc contract name
80 |
81 | You can obtain, by its Arc contract name, any wrapper deployed by the running version of Arc.js:
82 |
83 | ```javascript
84 | import { ContractWrappers } from "@daostack/arc.js";
85 | const upgradeScheme = ContractWrappers.UpgradeScheme;
86 | ```
87 |
88 |
89 | ## Get a wrapper at a given address
90 |
91 | You can use a wrapper's factory class to obtain a wrapper for a contract deployed to any given address:
92 |
93 | ```javascript
94 | import { UpgradeSchemeFactory} from "@daostack/arc.js";
95 | const upgradeScheme = await UpgradeSchemeFactory.at(someAddress);
96 | ```
97 |
98 | !!! info
99 | `.at` will return `undefined` if it can't find the contract at the given address.
100 |
101 | Another way to get a wrapper at a given address is using [WrapperService.getContractWrapper](/arc.js/api/classes/WrapperService#getContractWrapper). This is most useful when you have a contract name
102 | and may or may not have an address and wish to most efficiently return the associated wrapper, or undefined when not found:
103 |
104 | ```javascript
105 | import { WrapperService } from "@daostack/arc.js";
106 | // returns undefined when not found, unlike the factory `.at` which throws an exception
107 | const upgradeScheme = await WrapperService.getContractWrapper("UpgradeScheme", someAddressThatMayBeUndefined);
108 | }
109 | ```
110 |
111 |
112 | ## Deploy a new contract
113 |
114 | You can use a wrapper's factory class to deploy a new instance of a contract and obtain a wrapper for it:
115 |
116 | ```javascript
117 | import { UpgradeSchemeFactory} from "@daostack/arc.js";
118 | const newUpgradeScheme = await UpgradeSchemeFactory.new();
119 | ```
120 |
121 |
122 | ## Enumerate all of the deployed wrappers
123 |
124 | You can enumerate all of the wrappers of contracts deployed by the running version of Arc.js:
125 |
126 | ```javascript
127 | import { ContractWrappers } from "@daostack/arc.js";
128 | for (var wrapper in ContractWrappers) {
129 | console.log(`${wrapper.friendlyName} is at ${wrapper.address}`);
130 | }
131 | ```
132 |
133 |
134 | ## Enumerate wrappers by contract type
135 |
136 | You can enumerate the wrappers by contract category, for example, universalSchemes:
137 |
138 | ```javascript
139 | import { ContractWrappersByType } from "@daostack/arc.js";
140 | for (var schemeWrapper of ContractWrappersByType.universalSchemes) {
141 | console.log(`${schemeWrapper.friendlyName} is at ${schemeWrapper.address}`);
142 | }
143 | ```
144 |
145 | The set of contract categories is defined in [ArcWrappersByType](/arc.js/api/interfaces/ArcWrappersByType).
146 |
147 | ## Can't Find What You Need?
148 |
149 | Arc.js doesn't wrap every Arc contact nor give you a helper class for everything, but it does give you some more options described in the following sections.
150 |
151 | ### Truffle Contracts and Web3
152 |
153 | Under the hood Arc.js uses Truffle contracts and `Web3`. When you find that Arc.js doesn't directly provide you a piece of information or functionality that you need, you might be able to use them to find what you want. You can obtain `Web3` via [Utils.getWeb3](/arc.js/api/classes/Utils#getWeb3) and the Truffle contract associated with each contract wrapper instance via the `contract` property on each wrapper class.
154 |
155 | !!! info "More on `Web3` and Truffle contracts"
156 | - [Web3](https://github.com/ethereum/wiki/wiki/JavaScript-API)
157 | - [Truffle contracts](https://github.com/trufflesuite/truffle-contract)
158 |
159 | ### Undeployed Arc Contracts
160 |
161 | Some Arc contracts are wrapped but not deployed by Arc.js, for example `DaoToken` and others. `ContractWrappers` (`WrapperService.wrappers`) will not contain entries for these wrappers since they are not deployed. But you will find their factories where you can use `.at`. or `.new`.
162 |
163 | ### Unwrapped Arc Contracts
164 |
165 | Not all Arc contracts have been given wrapper classes, for example, `Avatar`, `UController` and many more. But using `Utils.requireContract` you can obtain a raw [Truffle contract](https://github.com/trufflesuite/truffle-contract) for any contract, enabling you to work with the contract just by providing the name of the Arc contract:
166 |
167 | ```javascript
168 | import { Utils } from "@daostack/arc.js";
169 | const avatarTruffleContract = await Utils.requireContract("Avatar");
170 | ```
171 |
172 | !!! info
173 | `Utils.requireContract` throws an exception when there is any problem creating the truffle contract object.
174 |
175 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/accountService.ts:
--------------------------------------------------------------------------------
1 | import { promisify } from "es6-promisify";
2 | import { Address } from "./commonTypes";
3 | import { LoggingService } from "./loggingService";
4 | import { IEventSubscription, PubSubEventService } from "./pubSubEventService";
5 | import { Utils } from "./utils";
6 |
7 | /**
8 | * Watch for changes in the default account.
9 | *
10 | * For more information, see [Account Changes](/Configuration.md#accountchanges).
11 | */
12 | export class AccountService {
13 |
14 | public static AccountChangedEventTopic: string = "AccountService.account.changed";
15 | public static NetworkChangedEventTopic: string = "AccountService.network.changed";
16 |
17 | /**
18 | * Initializes the system that watches for default account changes.
19 | *
20 | * `initiateAccountWatch` is called automatically by Arc.js when you pass `true`
21 | * for `watchForAccountChanges` to `InitializeArcJs`. You may also call it manually yourself.
22 | *
23 | * Then you may request to be notified whenever the current account changes by calling
24 | * [AccountService.subscribeToAccountChanges](/arc.js/api/classes/AccountService#subscribeToAccountChanges)
25 | */
26 | public static async initiateAccountWatch(): Promise {
27 |
28 | if (AccountService.accountChangedTimerId) {
29 | return;
30 | }
31 |
32 | LoggingService.info("Initiating account watch");
33 |
34 | if (!AccountService.currentAccount) {
35 | try {
36 | AccountService.currentAccount = await Utils.getDefaultAccount();
37 | } catch {
38 | AccountService.currentAccount = undefined;
39 | }
40 | }
41 |
42 | AccountService.accountChangedTimerId = setInterval(async () => {
43 |
44 | if (AccountService.accountChangedLock) {
45 | return; // prevent reentrance
46 | }
47 |
48 | AccountService.accountChangedLock = true;
49 |
50 | let currentAccount = AccountService.currentAccount;
51 | try {
52 | currentAccount = await Utils.getDefaultAccount();
53 | } catch {
54 | currentAccount = undefined;
55 | }
56 | if (currentAccount !== AccountService.currentAccount) {
57 | AccountService.currentAccount = currentAccount;
58 | LoggingService.info(`Account watch: account changed: ${currentAccount}`);
59 | PubSubEventService.publish(AccountService.AccountChangedEventTopic, currentAccount);
60 | }
61 | AccountService.accountChangedLock = false;
62 | }, 1000);
63 | }
64 |
65 | /**
66 | * Initializes the system that watches for blockchain network id changes.
67 | *
68 | * `initiateNetworkWatch` is called automatically by Arc.js when you pass `true`
69 | * for `watchForNetworkChanges` to `InitializeArcJs`. You may also call it manually yourself.
70 | *
71 | * Then you may request to be notified whenever the current account changes by calling
72 | * [AccountService.subscribeToNetworkChanges](/arc.js/api/classes/AccountService#subscribeToNetworkChanges)
73 | *
74 | * When the network is found to have changed you should call `InitializeArcJs` so Arc.js will set
75 | * itself up with the new network and return to you a new `Web3` object.
76 | */
77 | public static async initiateNetworkWatch(): Promise {
78 |
79 | if (AccountService.networkChangedTimerId) {
80 | return;
81 | }
82 |
83 | LoggingService.info("Initiating account watch");
84 |
85 | if (!AccountService.currentNetworkId) {
86 | try {
87 | AccountService.currentNetworkId = await AccountService.getNetworkId();
88 | } catch {
89 | AccountService.currentNetworkId = undefined;
90 | }
91 | }
92 |
93 | AccountService.networkChangedTimerId = setInterval(async () => {
94 |
95 | if (AccountService.networkChangedLock) {
96 | return; // prevent reentrance
97 | }
98 |
99 | AccountService.networkChangedLock = true;
100 |
101 | let currentNetworkId = AccountService.currentNetworkId;
102 | try {
103 | currentNetworkId = await AccountService.getNetworkId();
104 | } catch {
105 | currentNetworkId = undefined;
106 | }
107 | if (currentNetworkId !== AccountService.currentNetworkId) {
108 | AccountService.currentNetworkId = currentNetworkId;
109 | LoggingService.info(`Network watch: network changed: ${currentNetworkId}`);
110 | PubSubEventService.publish(AccountService.NetworkChangedEventTopic, currentNetworkId);
111 | }
112 | AccountService.networkChangedLock = false;
113 | }, 1000);
114 | }
115 | /**
116 | * Turn off the system that watches for default account changes.
117 | */
118 | public static endAccountWatch(): void {
119 | if (AccountService.accountChangedTimerId) {
120 | clearInterval(AccountService.accountChangedTimerId);
121 | AccountService.accountChangedTimerId = undefined;
122 | }
123 | }
124 |
125 | /**
126 | * Turn off the system that watches for default account changes.
127 | */
128 | public static endNetworkWatch(): void {
129 | if (AccountService.networkChangedTimerId) {
130 | clearInterval(AccountService.networkChangedTimerId);
131 | AccountService.networkChangedTimerId = undefined;
132 | }
133 | }
134 | /**
135 | * Subscribe to be notified whenever the current account changes, like this:
136 | *
137 | * ```typescript
138 | * AccountService.subscribeToAccountChanges((account: Address): void => { ... });
139 | * ```
140 | * @param callback
141 | * @returns A subscription to the event. Unsubscribe by calling `[theSubscription].unsubscribe()`.
142 | */
143 | public static subscribeToAccountChanges(callback: (address: Address) => void): IEventSubscription {
144 | return PubSubEventService.subscribe(AccountService.AccountChangedEventTopic,
145 | (topic: string, address: Address): any => callback(address));
146 | }
147 |
148 | /**
149 | * Subscribe to be notified whenever the current network changes, like this:
150 | *
151 | * ```typescript
152 | * AccountService.subscribeToAccountChanges((networkId: number): void => { ... });
153 | * ```
154 | * @param callback
155 | * @returns A subscription to the event. Unsubscribe by calling `[theSubscription].unsubscribe()`.
156 | */
157 | public static subscribeToNetworkChanges(callback: (networkId: number) => void): IEventSubscription {
158 | return PubSubEventService.subscribe(AccountService.NetworkChangedEventTopic,
159 | (topic: string, networkId: number): any => callback(networkId));
160 | }
161 |
162 | private static currentAccount: Address | undefined;
163 | private static currentNetworkId: number | undefined;
164 | private static accountChangedLock: boolean = false;
165 | private static accountChangedTimerId: any;
166 | private static networkChangedLock: boolean = false;
167 | private static networkChangedTimerId: any;
168 |
169 | private static async getNetworkId(): Promise {
170 | const web3 = await Utils.getWeb3();
171 | return web3 ?
172 | Number.parseInt(await promisify(web3.version.getNetwork)() as string, 10) as number | undefined : undefined;
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/lib/avatarService.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from "bignumber.js";
2 | import { promisify } from "es6-promisify";
3 | import { Address } from "./commonTypes";
4 | import { ControllerService } from "./controllerService";
5 | import { LoggingService } from "./loggingService";
6 | import { Utils } from "./utils";
7 | import { DaoTokenFactory, DaoTokenWrapper } from "./wrappers/daoToken";
8 | import { ReputationFactory, ReputationWrapper } from "./wrappers/reputation";
9 |
10 | /**
11 | * Methods for querying information about an Avatar.
12 | * Use it by:
13 | *
14 | * ```javascript
15 | * const avatarService = new AvatarService(avatarAddress);
16 | * ```
17 | *
18 | */
19 | export class AvatarService {
20 |
21 | public controllerService: ControllerService;
22 | private avatarAddress: Address;
23 | private avatar: any;
24 | private nativeReputationAddress: any;
25 | private nativeReputation: ReputationWrapper;
26 | private nativeTokenAddress: any;
27 | private nativeToken: DaoTokenWrapper;
28 |
29 | constructor(avatarAddress: Address) {
30 | this.avatarAddress = avatarAddress;
31 | this.controllerService = new ControllerService(avatarAddress);
32 | }
33 |
34 | /**
35 | * Returns promise of the Avatar Truffle contract wrapper.
36 | * Returns undefined if not found.
37 | */
38 | public async getAvatar(): Promise {
39 | if (!this.avatar) {
40 | const Avatar = await Utils.requireContract("Avatar");
41 | return Avatar.at(this.avatarAddress)
42 | .then((avatar: any) => avatar) // only way to get to catch
43 |
44 | /* have to handle the catch or promise rejection goes unhandled */
45 | .catch((ex: Error) => {
46 | LoggingService.error(`AvatarService: unable to load avatar at ${this.avatarAddress}: ${ex.message}`);
47 | return undefined;
48 | });
49 | }
50 | }
51 |
52 | public getIsUController(): Promise {
53 | return this.controllerService.getIsUController();
54 | }
55 |
56 | /**
57 | * Returns promise of the address of the controller
58 | */
59 | public async getControllerAddress(): Promise {
60 | return this.controllerService.getControllerAddress();
61 | }
62 |
63 | /**
64 | * Returns promise of a Truffle contract wrapper for the controller. Could be
65 | * either UController or Controller. You can know which one
66 | * by called `getIsUController`.
67 | */
68 | public async getController(): Promise {
69 | return this.controllerService.getController();
70 | }
71 |
72 | /**
73 | * Returns promise of the address of the avatar's native reputation.
74 | */
75 | public async getNativeReputationAddress(): Promise {
76 | if (!this.nativeReputationAddress) {
77 | const avatar = await this.getAvatar();
78 | if (avatar) {
79 | this.nativeReputationAddress = await avatar.nativeReputation();
80 | }
81 | }
82 | return this.nativeReputationAddress;
83 | }
84 |
85 | /**
86 | * Returns promise of the avatar's native reputation Truffle contract wrapper.
87 | */
88 | public async getNativeReputation(): Promise {
89 | if (!this.nativeReputation) {
90 | const reputationAddress = await this.getNativeReputationAddress();
91 | if (reputationAddress) {
92 | this.nativeReputation = await ReputationFactory.at(reputationAddress);
93 | }
94 | }
95 | return this.nativeReputation;
96 | }
97 |
98 | /**
99 | * Returns promise of the address of the avatar's native token.
100 | */
101 | public async getNativeTokenAddress(): Promise {
102 | if (!this.nativeTokenAddress) {
103 | const avatar = await this.getAvatar();
104 | if (avatar) {
105 | this.nativeTokenAddress = await avatar.nativeToken();
106 | }
107 | }
108 | return this.nativeTokenAddress;
109 | }
110 |
111 | /**
112 | * Returns promise of the avatar's native token Truffle contract wrapper.
113 | * Assumes the token is a `DAOToken`.
114 | */
115 | public async getNativeToken(): Promise {
116 | if (!this.nativeToken) {
117 | const tokenAddress = await this.getNativeTokenAddress();
118 | if (tokenAddress) {
119 | this.nativeToken = await DaoTokenFactory.at(tokenAddress);
120 | }
121 | }
122 | return this.nativeToken;
123 | }
124 |
125 | /**
126 | * Return a current token balance for this avatar, in Wei.
127 | * If tokenAddress is not supplied, then uses native token.
128 | */
129 | public async getTokenBalance(tokenAddress?: Address): Promise {
130 | let token: DaoTokenWrapper;
131 |
132 | if (!tokenAddress) {
133 | token = await this.getNativeToken();
134 | } else {
135 | token = await DaoTokenFactory.at(tokenAddress);
136 | }
137 | if (!token) {
138 | LoggingService.error(`AvatarService: Unable to load token at ${tokenAddress}`);
139 | return Promise.resolve(undefined);
140 | }
141 | return token.getBalanceOf(this.avatarAddress);
142 | }
143 |
144 | /**
145 | * Return the current ETH balance for this avatar, in Wei.
146 | */
147 | public async getEthBalance(): Promise {
148 | const web3 = await Utils.getWeb3();
149 |
150 | return promisify((callback: any) => web3.eth.getBalance(this.avatarAddress, web3.eth.defaultBlock, callback))()
151 | .then((balance: BigNumber) => {
152 | return balance;
153 | });
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/lib/commonTypes.ts:
--------------------------------------------------------------------------------
1 | import { Utils } from "./utils";
2 |
3 | export type fnVoid = () => void;
4 | export type Hash = string;
5 | export type Address = string;
6 |
7 | export enum BinaryVoteResult {
8 | Abstain = 0,
9 | Yes = 1,
10 | No = 2,
11 | }
12 |
13 | export enum SchemePermissions {
14 | None = 0,
15 | /**
16 | * A scheme always automatically gets this bit when registered to a DAO
17 | */
18 | IsRegistered = 1,
19 | CanRegisterSchemes = 2,
20 | CanAddRemoveGlobalConstraints = 4,
21 | CanUpgradeController = 8,
22 | CanCallDelegateCall = 0x10,
23 | All = 0x1f,
24 | }
25 | /* tslint:disable:no-bitwise */
26 | /* tslint:disable:max-line-length */
27 | /**
28 | * These are the permissions that are the minimum that each scheme must have to
29 | * be able to perform its full range of functionality.
30 | *
31 | * Note that '1' is always assigned to a scheme by the Controller when the
32 | * scheme is registered with the controller.
33 | */
34 | export class DefaultSchemePermissions {
35 | public static NoPermissions: SchemePermissions = SchemePermissions.None;
36 | public static MinimumPermissions: SchemePermissions = SchemePermissions.IsRegistered;
37 | public static AllPermissions: SchemePermissions = SchemePermissions.All;
38 | public static ContributionReward: SchemePermissions = SchemePermissions.IsRegistered;
39 | public static GlobalConstraintRegistrar: SchemePermissions = SchemePermissions.IsRegistered | SchemePermissions.CanAddRemoveGlobalConstraints;
40 | /**
41 | * Has all permissions so that it can register/unregister all schemes
42 | */
43 | public static SchemeRegistrar: SchemePermissions = SchemePermissions.All;
44 | public static UpgradeScheme: SchemePermissions = SchemePermissions.IsRegistered | SchemePermissions.CanRegisterSchemes | SchemePermissions.CanUpgradeController;
45 | public static VestingScheme: SchemePermissions = SchemePermissions.IsRegistered;
46 | public static VoteInOrganizationScheme: SchemePermissions = SchemePermissions.IsRegistered | SchemePermissions.CanCallDelegateCall;
47 | }
48 | /* tslint:enable:no-bitwise */
49 | /* tslint:enable:max-line-length */
50 | /* tslint:disable:no-namespace */
51 | export namespace SchemePermissions {
52 | export function toString(perms: SchemePermissions): string {
53 | return Utils.numberToPermissionsString(perms);
54 | }
55 | export function fromString(perms: string): SchemePermissions {
56 | return Utils.permissionsStringToNumber(perms);
57 | }
58 | }
59 | /*tslint:enable:no-namespace */
60 |
61 | export interface TruffleContract {
62 | /**
63 | * Migrate a new instance of the contract. Returns promise of being
64 | * migrated.
65 | * Note that the so-called promise returned by Truffle only supplies a 'then'
66 | * function, You have to call 'then' to get the real promise.
67 | */
68 | new: (...rest: Array) => Promise;
69 | /**
70 | * Returns a promise of an existing instance of the contract.
71 | * Note that the so-called promise returned by Truffle only supplies a 'then'
72 | * function, You have to call 'then' to get the real promise.
73 | */
74 | at: (address: string) => Promise;
75 | /**
76 | * Returns a promise of the deployed instance of the contract.
77 | * Note that the so-called promise returned by Truffle only supplies a 'then'
78 | * function, You have to call 'then' to get the real promise.
79 | */
80 | deployed: () => Promise;
81 | }
82 |
--------------------------------------------------------------------------------
/lib/configService.ts:
--------------------------------------------------------------------------------
1 | import { IConfigService } from "./iConfigService";
2 | import { PubSubEventService } from "./pubSubEventService";
3 |
4 | /**
5 | * Set and set global Arc.js settings.
6 | *
7 | * For more information, refer to [Configuring Arc.js](/Configuration.md).
8 | */
9 | export class ConfigService {
10 | public static instance: IConfigService;
11 | public static data: any;
12 |
13 | public static get(setting: string): any {
14 | const parts = setting.split(".");
15 | let result;
16 | if (parts.length) {
17 | result = ConfigService.data;
18 | parts.forEach((part: any): void => {
19 | result = result[part];
20 | });
21 | }
22 | return result;
23 | }
24 |
25 | public static set(setting: string, value: any): void {
26 | const parts = setting.split(".");
27 | const count = parts.length - 1;
28 | let section = ConfigService.data;
29 | if (count > 0) {
30 | for (let i = 0; i < count; ++i) {
31 | section = section[parts[i]];
32 | }
33 | }
34 | section[parts[count]] = value;
35 | PubSubEventService.publish(`ConfigService.settingChanged.${setting}`, value);
36 | }
37 |
38 | constructor() {
39 | if (!ConfigService.instance) {
40 | const defaults = require("../config/default.json");
41 | const prefix = "arcjs_";
42 | if (process && process.env) {
43 | Object.keys(process.env).forEach((key: string) => {
44 | if (key.startsWith(prefix)) {
45 | const internalKey = key.replace(prefix, "");
46 | if (defaults.hasOwnProperty(internalKey)) {
47 | defaults[internalKey] = process.env[key];
48 | }
49 | }
50 | });
51 | }
52 |
53 | ConfigService.data = defaults;
54 | ConfigService.instance = this;
55 | }
56 | return ConfigService.instance;
57 | }
58 |
59 | public get(setting: string): any {
60 | return ConfigService.instance.get(setting);
61 | }
62 |
63 | public set(setting: string, value: any): void {
64 | ConfigService.instance.set(setting, value);
65 | }
66 | }
67 |
68 | /**
69 | * This will automagically create a static instance of ConfigService that will be used whenever
70 | * someone imports ConfigService.
71 | */
72 | Object.freeze(new ConfigService());
73 |
--------------------------------------------------------------------------------
/lib/contractWrapperFactory.ts:
--------------------------------------------------------------------------------
1 | import { promisify } from "es6-promisify";
2 | import { Address } from "./commonTypes";
3 | import { ConfigService } from "./configService";
4 | import { IConfigService } from "./iConfigService";
5 | import { IContractWrapper, IContractWrapperFactory } from "./iContractWrapperBase";
6 | import { LoggingService } from "./loggingService";
7 | import { Utils } from "./utils";
8 | import { UtilsInternal } from "./utilsInternal";
9 | import { Web3EventService } from "./web3EventService";
10 |
11 | /**
12 | * Generic class factory for all of the contract wrapper classes.
13 | */
14 | export class ContractWrapperFactory
15 | implements IContractWrapperFactory {
16 |
17 | public static setConfigService(configService: IConfigService): void {
18 | this.configService = configService;
19 | }
20 |
21 | public static clearContractCache(): void {
22 | this.contractCache.clear();
23 | }
24 |
25 | /**
26 | * this is a Map keyed by contract name of a Map keyed by address to an `IContractWrapper`
27 | */
28 | private static contractCache: Map>
29 | = new Map>();
30 |
31 | private static configService: IConfigService;
32 |
33 | private solidityContract: any;
34 |
35 | /**
36 | * Connstructor to create a contract wrapper factory for the given
37 | * Arc contract name and wrapper class.
38 | * @param solidityContract Name of the contract
39 | * @param wrapper - Class of the contract
40 | */
41 | public constructor(
42 | private solidityContractName: string,
43 | private wrapper: new (solidityContract: any, web3EventService: Web3EventService) => TWrapper,
44 | private web3EventService: Web3EventService) {
45 | }
46 |
47 | /**
48 | * Deploy a new instance of the contract and return a wrapper around it.
49 | * @param rest Optional arguments to the Arc contracts constructor.
50 | */
51 | public async new(...rest: Array): Promise {
52 |
53 | await this.ensureSolidityContract();
54 |
55 | let gas;
56 |
57 | if (ConfigService.get("estimateGas") && (!rest || !rest.length || (!rest[rest.length - 1].gas))) {
58 | gas = await this.estimateConstructorGas(...rest);
59 | LoggingService.debug(`Instantiating ${this.solidityContractName} with gas: ${gas}`);
60 | }
61 |
62 | if (gas) {
63 | rest = [...rest, { gas }];
64 | }
65 |
66 | const hydratedWrapper =
67 | await new this.wrapper(this.solidityContract, this.web3EventService).hydrateFromNew(...rest);
68 |
69 | if (hydratedWrapper && ContractWrapperFactory.configService.get("cacheContractWrappers")) {
70 | this.setCachedContract(this.solidityContractName, hydratedWrapper);
71 | }
72 | return hydratedWrapper;
73 | }
74 |
75 | /**
76 | * Return a wrapper around the contract, hydrated from the given address.
77 | * Returns undefined if not found.
78 | * @param address
79 | */
80 | public async at(address: string): Promise {
81 |
82 | await this.ensureSolidityContract();
83 |
84 | const getWrapper = (): Promise => {
85 | return new this.wrapper(this.solidityContract, this.web3EventService).hydrateFromAt(address);
86 | };
87 |
88 | return this.getHydratedWrapper(getWrapper, address);
89 | }
90 |
91 | /**
92 | * Return a wrapper around the contract as deployed by the current version of Arc.js.
93 | * Note this is usually not needed as the WrapperService provides these
94 | * wrappers already hydrated.
95 | * Returns undefined if not found.
96 | */
97 | public async deployed(): Promise {
98 | /**
99 | * use deployed address if supplied for this contract
100 | */
101 | const externallyDeployedAddress = Utils.getDeployedAddress(this.solidityContractName);
102 |
103 | if (!externallyDeployedAddress) {
104 | throw new Error("ContractWrapperFactory: No deployed contract address has been supplied.");
105 | }
106 |
107 | return this.at(externallyDeployedAddress);
108 | }
109 |
110 | public async ensureSolidityContract(): Promise {
111 | /**
112 | * requireContract caches and uncaches the contract appropriately
113 | */
114 | return Utils.requireContract(this.solidityContractName)
115 | .then((contract: any): any => this.solidityContract = contract);
116 | }
117 |
118 | protected async estimateConstructorGas(...params: Array): Promise {
119 |
120 | const web3 = await Utils.getWeb3();
121 | await this.ensureSolidityContract();
122 |
123 | const callData = (web3.eth.contract(this.solidityContract.abi).new as any).getData(
124 | ...params,
125 | {
126 | data: this.solidityContract.bytecode,
127 | });
128 |
129 | const currentNetwork = await Utils.getNetworkName();
130 |
131 | const maxGasLimit = await UtilsInternal.computeMaxGasLimit();
132 |
133 | // note that Ganache is identified specifically as the one instantiated by arc.js (by the networkId)
134 | if (currentNetwork === "Ganache") {
135 | return maxGasLimit; // because who cares with ganache and we can't get good estimates from it
136 | }
137 |
138 | const gas = await promisify((callback: any) => web3.eth.estimateGas({ data: callData }, callback))() as number;
139 |
140 | return Math.max(Math.min(gas, maxGasLimit), 21000);
141 | }
142 |
143 | private async getHydratedWrapper(
144 | getWrapper: () => Promise,
145 | address?: Address): Promise {
146 |
147 | let hydratedWrapper: TWrapper;
148 | if (ContractWrapperFactory.configService.get("cacheContractWrappers")) {
149 | if (!address) {
150 | try {
151 | address = this.solidityContract.address;
152 | } catch {
153 | // the contract has not been deployed, so can't get it's address
154 | }
155 | }
156 |
157 | if (address) {
158 | hydratedWrapper = this.getCachedContract(this.solidityContractName, address) as TWrapper;
159 | if (hydratedWrapper) {
160 | LoggingService.debug(`ContractWrapperFactory: obtained wrapper from cache: ${hydratedWrapper.address}`);
161 | }
162 | }
163 |
164 | if (!hydratedWrapper) {
165 | hydratedWrapper = await getWrapper();
166 | if (hydratedWrapper) {
167 | this.setCachedContract(this.solidityContractName, hydratedWrapper);
168 | }
169 | }
170 | } else {
171 | hydratedWrapper = await getWrapper();
172 | }
173 | return hydratedWrapper;
174 | }
175 |
176 | private getCachedContract(name: string, at: string): IContractWrapper | undefined {
177 | if (!at) {
178 | return undefined;
179 | }
180 | const addressMap = ContractWrapperFactory.contractCache.get(name);
181 | if (!addressMap) {
182 | return undefined;
183 | }
184 | return addressMap.get(at);
185 | }
186 |
187 | private setCachedContract(
188 | name: string,
189 | wrapper: IContractWrapper): void {
190 |
191 | if (wrapper) {
192 | let addressMap = ContractWrapperFactory.contractCache.get(name);
193 | if (!addressMap) {
194 | addressMap = new Map();
195 | ContractWrapperFactory.contractCache.set(name, addressMap);
196 | }
197 | addressMap.set(wrapper.address, wrapper);
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/lib/controllerService.ts:
--------------------------------------------------------------------------------
1 | import { Address } from "./commonTypes";
2 | import { LoggingService } from "./loggingService";
3 | import { Utils } from "./utils";
4 |
5 | /**
6 | * Methods for querying information about an Avatar's controller.
7 | * Use it by:
8 | *
9 | * ```javascript
10 | * const controllerService = new ControllerService(avatarAddress);
11 | * ```
12 | *
13 | */
14 | export class ControllerService {
15 |
16 | private isUController: boolean;
17 | private avatarAddress: Address;
18 | private avatar: any;
19 | private controllerAddress: any;
20 | private controller: any;
21 |
22 | constructor(avatarAddress: Address) {
23 | this.avatarAddress = avatarAddress;
24 | this.isUController = undefined;
25 | }
26 |
27 | /**
28 | * Returns promise of whether avatar has a universal controller
29 | */
30 | public async getIsUController(): Promise {
31 | await this.getController();
32 | return this.isUController;
33 | }
34 |
35 | /**
36 | * Returns promise of the address of the controller
37 | */
38 | public async getControllerAddress(): Promise {
39 | if (!this.controllerAddress) {
40 | const avatar = await this.getAvatar();
41 | if (avatar) {
42 | this.controllerAddress = await avatar.owner();
43 | }
44 | }
45 | return this.controllerAddress;
46 | }
47 |
48 | /**
49 | * Returns promise of a Truffle contract wrapper for the controller. Could be
50 | * either UController or Controller. You can know which one
51 | * by checking the ControllerService instance property `isUController`.
52 | */
53 | public async getController(): Promise {
54 |
55 | if (!this.controller) {
56 | const controllerAddress = await this.getControllerAddress();
57 | if (controllerAddress) {
58 | /**
59 | * anticipate case where UController hasn't been deployed
60 | */
61 | let uControllerAddress;
62 | let UControllerContract;
63 | try {
64 | /**
65 | * TODO: check for previous and future versions of UController here
66 | */
67 | UControllerContract = await Utils.requireContract("UController");
68 | uControllerAddress = (await UControllerContract.deployed()).address;
69 | /* tslint:disable-next-line:no-empty */
70 | } catch { }
71 |
72 | this.isUController = uControllerAddress === controllerAddress;
73 |
74 | if (this.isUController) {
75 | this.controller = await UControllerContract.at(controllerAddress);
76 | } else {
77 | const ControllerContract = await Utils.requireContract("Controller");
78 | this.controller = await ControllerContract.at(controllerAddress);
79 | }
80 | }
81 | }
82 | return this.controller;
83 | }
84 |
85 | /**
86 | * Returns promise of the Avatar Truffle contract wrapper.
87 | * Returns undefined if not found.
88 | */
89 | private async getAvatar(): Promise {
90 | if (!this.avatar) {
91 | const Avatar = await Utils.requireContract("Avatar");
92 | return Avatar.at(this.avatarAddress)
93 | .then((avatar: any) => avatar) // only way to get to catch
94 |
95 | /* have to handle the catch or promise rejection goes unhandled */
96 | .catch((ex: Error) => {
97 | LoggingService.error(`ControllerService: unable to load avatar at ${this.avatarAddress}: ${ex.message}`);
98 | return undefined;
99 | });
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/lib/iConfigService.ts:
--------------------------------------------------------------------------------
1 | export interface IConfigService {
2 | get(setting: string): any;
3 | set(setting: string, value: any): void;
4 | }
5 |
--------------------------------------------------------------------------------
/lib/iContractWrapperBase.ts:
--------------------------------------------------------------------------------
1 | import BigNumber from "bignumber.js";
2 | import { Address, Hash, SchemePermissions } from "./commonTypes";
3 | import {
4 | TransactionReceiptTruffle,
5 | TransactionService
6 | } from "./transactionService";
7 | import { IIntVoteInterface } from "./wrappers/iIntVoteInterface";
8 |
9 | export interface IContractWrapper {
10 | factory: IContractWrapperFactory;
11 | name: string;
12 | friendlyName: string;
13 | address: Address;
14 | contract: any;
15 | hydrateFromNew(...rest: Array): Promise;
16 | hydrateFromAt(address: string): Promise;
17 | }
18 |
19 | /**
20 | * The minimum requirements for a scheme that can be registered with a DAO/controller.
21 | */
22 | export interface ISchemeWrapper extends IContractWrapper {
23 | getSchemePermissions(avatarAddress: Address): Promise;
24 | getDefaultPermissions(): SchemePermissions;
25 | }
26 |
27 | /**
28 | * The minimum requirements for a universal scheme.
29 | */
30 | export interface IUniversalSchemeWrapper extends ISchemeWrapper {
31 | getParameters(paramsHash: Hash): Promise;
32 | getParametersHash(params: any): Promise;
33 | setParameters(params: any): Promise>;
34 | getSchemeParameters(avatarAddress: Address): Promise;
35 | getParametersArray(paramsHash: Hash): Promise>;
36 | }
37 |
38 | /**
39 | * The minimum requirements for a voting machine wrapper.
40 | */
41 | export interface IVotingMachineWrapper extends IContractWrapper {
42 | getParameters(paramsHash: Hash): Promise;
43 | getParametersHash(params: any): Promise;
44 | setParameters(params: any): Promise>;
45 | getParametersArray(paramsHash: Hash): Promise>;
46 | }
47 |
48 | export interface IContractWrapperFactory {
49 | new: (...rest: Array) => Promise;
50 | at: (address: string) => Promise;
51 | deployed: () => Promise;
52 | ensureSolidityContract(): Promise;
53 | }
54 |
55 | export class ArcTransactionResult {
56 |
57 | constructor(
58 | /**
59 | * The transaction hash
60 | */
61 | public tx: Hash,
62 | /**
63 | * the Truffle contract wrapper
64 | */
65 | private contract: string | object) {
66 | }
67 |
68 | /**
69 | * Returns a promise of the transaction if it is mined,
70 | * converted to a TransactionReceiptTruffle (with readable logs).
71 | *
72 | * Returns null if the transaciton is not yet mined.
73 | */
74 | public async getTxMined(): Promise {
75 | if (!this.tx) {
76 | return null;
77 | }
78 | return TransactionService.getMinedTransaction(
79 | this.tx,
80 | this.contract) as Promise;
81 | }
82 |
83 | /**
84 | * Returns a promise of the transaction if it is confirmed,
85 | * converted to a TransactionReceiptTruffle (with readable logs).
86 | *
87 | * Returns null if the transaction is not yet found at the required depth.
88 | *
89 | * @param requiredDepth Optional minimum block depth required to resolve the promise.
90 | * Default comes from the `ConfigService`.
91 | */
92 | public async getTxConfirmed(requiredDepth?: number): Promise {
93 | if (!this.tx) {
94 | return null;
95 | }
96 | return TransactionService.getConfirmedTransaction(
97 | this.tx,
98 | this.contract,
99 | requiredDepth) as Promise;
100 | }
101 |
102 | /**
103 | * Returns promise of a mined transaction once it has been mined,
104 | * converted to a TransactionReceiptTruffle (with readable logs).
105 | */
106 | public async watchForTxMined(): Promise {
107 | if (!this.tx) {
108 | return null;
109 | }
110 | return TransactionService.watchForMinedTransaction(
111 | this.tx,
112 | this.contract) as Promise;
113 | }
114 |
115 | /**
116 | * Returns a promise of a TransactionReceipt once the given transaction has been confirmed,
117 | * converted to a TransactionReceiptTruffle (with readable logs),
118 | * according to the optional `requiredDepth`.
119 | *
120 | * @param requiredDepth Optional minimum block depth required to resolve the promise.
121 | * Default comes from the `ConfigService`.
122 | */
123 | public async watchForTxConfirmed(requiredDepth?: number): Promise {
124 | if (!this.tx) {
125 | return null;
126 | }
127 | return TransactionService.watchForConfirmedTransaction(this.tx,
128 | this.contract,
129 | requiredDepth) as Promise;
130 | }
131 |
132 | /**
133 | * Returns promise of a value from the logs of the mined transaction. Will watch for the mined tx,
134 | * so could take a while to return.
135 | * @param valueName - The name of the property whose value we wish to return
136 | * @param eventName - Name of the event in whose log we are to look for the value
137 | * @param index - Index of the log in which to look for the value, when eventName is not given.
138 | * Default is the index of the last log in the transaction.
139 | */
140 | public async getValueFromMinedTx(
141 | valueName: string,
142 | eventName: string = null, index: number = 0): Promise {
143 | if (!this.tx) {
144 | return null;
145 | }
146 | const txMined = await this.watchForTxMined();
147 | return TransactionService.getValueFromLogs(txMined, valueName, eventName, index);
148 | }
149 | }
150 | /**
151 | * Base or actual type returned by all contract wrapper methods that generate a transaction and initiate a proposal.
152 | */
153 | export class ArcTransactionProposalResult extends ArcTransactionResult {
154 |
155 | constructor(
156 | tx: Hash,
157 | contract: any,
158 | /**
159 | * The proposal's voting machine, as IntVoteInterface
160 | */
161 | public votingMachine: IIntVoteInterface) {
162 | super(tx, contract);
163 | this.votingMachine = votingMachine;
164 | }
165 |
166 | /**
167 | * Returns promise of the proposal id from the logs of the mined transaction. Will watch for the mined tx;
168 | * if it hasn't yet been mined, could take a while to return.
169 | */
170 | public async getProposalIdFromMinedTx(): Promise {
171 | return this.getValueFromMinedTx("_proposalId");
172 | }
173 | }
174 |
175 | /**
176 | * Base or actual type returned by all contract wrapper methods that generate a transaction and any other result.
177 | */
178 | export class ArcTransactionDataResult extends ArcTransactionResult {
179 | constructor(
180 | tx: Hash,
181 | contract: any,
182 | /**
183 | * Additional data being returned.
184 | */
185 | public result: TData) {
186 | super(tx, contract);
187 | this.result = result;
188 | }
189 | }
190 |
191 | /**
192 | * Common scheme parameters for schemes that are able to create proposals.
193 | */
194 | export interface StandardSchemeParams {
195 | /**
196 | * Hash of the voting machine parameters to use when voting on a proposal.
197 | */
198 | voteParametersHash: Hash;
199 | /**
200 | * Address of the voting machine to use when voting on a proposal.
201 | */
202 | votingMachineAddress: Address;
203 | }
204 |
205 | export { DecodedLogEntryEvent, TransactionReceipt } from "web3";
206 |
207 | /**
208 | * The value of the global config setting `gasPriceAdjustor`
209 | * This function will be invoked to obtain promise of a desired gas price
210 | * given the current default gas price which will be determined by the x latest blocks
211 | * median gas price.
212 | */
213 | export type GasPriceAdjustor = (defaultGasPrice: BigNumber) => Promise;
214 |
--------------------------------------------------------------------------------
/lib/loggingService.ts:
--------------------------------------------------------------------------------
1 | import * as JSON from "circular-json";
2 |
3 | export enum LogLevel {
4 | none = 0,
5 | info = 1,
6 | warn = 2,
7 | debug = 4,
8 | error = 8,
9 | all = 15,
10 | }
11 |
12 | export interface ILogger {
13 | /**
14 | * Logs a debug message.
15 | *
16 | * @param message The message to log.
17 | */
18 | debug(message: string): void;
19 |
20 | /**
21 | * Logs info.
22 | *
23 | * @param message The message to log.
24 | */
25 | info(message: string): void;
26 |
27 | /**
28 | * Logs a warning.
29 | *
30 | * @param message The message to log.
31 | */
32 | warn(message: string): void;
33 |
34 | /**
35 | * Logs an error.
36 | *
37 | * @param message The message to log.
38 | */
39 | error(message: string): void;
40 | }
41 |
42 | class ConsoleLogger implements ILogger {
43 |
44 | /* tslint:disable:max-line-length */
45 | /* tslint:disable:no-console */
46 | /* tslint:disable:no-bitwise */
47 | public debug(message: string): void { if (LoggingService.logLevel & LogLevel.debug) { console.log(`${LoggingService.moduleName} (debug): ${message}`); } }
48 |
49 | public info(message: string): void { if (LoggingService.logLevel & LogLevel.info) { console.log(`${LoggingService.moduleName} (info): ${message}`); } }
50 |
51 | public warn(message: string): void { if (LoggingService.logLevel & LogLevel.warn) { console.log(`${LoggingService.moduleName} (warn): ${message}`); } }
52 |
53 | public error(message: string): void { if (LoggingService.logLevel & LogLevel.error) { console.log(`${LoggingService.moduleName} (error): ${message}`); } }
54 | /* tslint:enable:no-console */
55 | /* tslint:enable:no-bitwise */
56 | /* tslint:enable:max-line-length */
57 | }
58 |
59 | /**
60 | * Provides logging support, logging by default to the JavaScript console. You can provide
61 | * alternate or additional loggers by using `LoggingService.addLogger` and `LoggingService.removeLogger`.
62 | *
63 | * You can set the `LogLevel` by setting `LoggingService.logLevel` with flags
64 | * from [LogLevel](/arc.js/api/enums/LogLevel/), or by using the [ConfigService](/Configuration.md#logging).
65 | *
66 | * Logically, LogLevels are simply or'd together, there is no hierarchy to them.
67 | */
68 | export class LoggingService {
69 |
70 | public static loggers: Array = [new ConsoleLogger()];
71 |
72 | public static logLevel: LogLevel = LogLevel.none;
73 |
74 | public static moduleName: string = "Arc.js";
75 |
76 | public static debug(message: string): void {
77 | LoggingService.loggers.forEach((logger: ILogger) => {
78 | logger.debug(message);
79 | });
80 | }
81 |
82 | public static info(message: string): void {
83 | LoggingService.loggers.forEach((logger: ILogger) => {
84 | logger.info(message);
85 | });
86 | }
87 |
88 | public static warn(message: string): void {
89 | LoggingService.loggers.forEach((logger: ILogger) => {
90 | logger.warn(message);
91 | });
92 | }
93 |
94 | public static error(message: string): void {
95 | LoggingService.loggers.forEach((logger: ILogger) => {
96 | logger.error(message);
97 | });
98 | }
99 |
100 | /**
101 | * Log a message at potentially multiple levels instead of just one.
102 | *
103 | * The message will be logged just once, at the first log level in the intersection between
104 | * the given log level and the current log level, in the following order of precendence:
105 | *
106 | * 1. error
107 | * 2. warn
108 | * 3. info
109 | * 4. debug
110 | *
111 | * So if the current log level is info|error and you call `message("a message", LogLevel.info|LogLevel.error)`
112 | * then you will see the message logged as an error.
113 | *
114 | * @param message
115 | * @param level log level(s)
116 | */
117 | public static message(message: string, level: LogLevel = LoggingService.logLevel): void {
118 |
119 | if (level === LogLevel.none) {
120 | return;
121 | }
122 |
123 | // only issue the message once
124 | let messaged: boolean = false;
125 |
126 | /* tslint:disable:no-bitwise */
127 | if (level & LogLevel.error) {
128 | LoggingService.error(message);
129 | messaged = true;
130 | }
131 | if (!messaged && (level & LogLevel.warn)) {
132 | LoggingService.warn(message);
133 | messaged = true;
134 | }
135 | if (!messaged && (level & LogLevel.info)) {
136 | LoggingService.info(message);
137 | messaged = true;
138 | }
139 | if (!messaged && (level & LogLevel.debug)) {
140 | LoggingService.debug(message);
141 | }
142 | /* tslint:enable:no-bitwise */
143 | }
144 |
145 | public static addLogger(logger: ILogger): void {
146 | LoggingService.loggers.push(logger);
147 | }
148 |
149 | public static removeLogger(logger: ILogger): void {
150 | const ndx = LoggingService.loggers.indexOf(logger);
151 | if (ndx >= 0) {
152 | LoggingService.loggers.splice(ndx, 1);
153 | }
154 | }
155 |
156 | public static stringifyObject(obj: any): string {
157 | return JSON.stringify(obj);
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/lib/promiseEventService.ts:
--------------------------------------------------------------------------------
1 | import { LoggingService } from "./loggingService";
2 | import { PubSubEventService } from "./pubSubEventService";
3 | import { UtilsInternal } from "./utilsInternal";
4 |
5 | export class PromiseEventService {
6 | /**
7 | * Publish to the given topics the result of the given promise.
8 | * The payload of the event will be of type TResult.
9 | * @param topics
10 | * @param promise
11 | */
12 | public static publish(topics: Array | string, promise: Promise): void {
13 | const topicsArray = UtilsInternal.ensureArray(topics);
14 | promise
15 | .then((result: TResult) => {
16 | topicsArray.forEach((topic: string) => {
17 | PubSubEventService.publish(topic, result);
18 | });
19 | })
20 | .catch((error: Error) => {
21 | LoggingService.error(
22 | `PromiseEventService.publish: unable to publish result of rejected promise: ${error.message}`);
23 | });
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/proposalGeneratorBase.ts:
--------------------------------------------------------------------------------
1 | import { Address } from "./commonTypes";
2 | import { ContractWrapperFactory } from "./contractWrapperFactory";
3 | import { ProposalService } from "./proposalService";
4 | import { USchemeWrapperBase } from "./uSchemeWrapperBase";
5 | import { Web3EventService } from "./web3EventService";
6 | import { IntVoteInterfaceFactory, IntVoteInterfaceWrapper } from "./wrappers/intVoteInterface";
7 |
8 | /**
9 | * Methods for Arc universal schemes that can create proposals. Note that a contract that
10 | * creates proposals doesn't necessary have to be a universal scheme, nor even a plain-old scheme.
11 | * But all of the Arc proposal-generating schemes currently are currently universal schemes, so
12 | * for the purposes of simplicity of organizating Arc.js and implementing these methods in one
13 | * place, we define this as a `USchemeWrapperBase`.
14 | */
15 | export abstract class ProposalGeneratorBase extends USchemeWrapperBase {
16 | protected proposalService: ProposalService;
17 | protected votingMachineFactory: ContractWrapperFactory;
18 |
19 | constructor(solidityContract: any, web3EventService: Web3EventService) {
20 | super(solidityContract, web3EventService);
21 | this.proposalService = new ProposalService(web3EventService);
22 | this.votingMachineFactory = IntVoteInterfaceFactory;
23 | }
24 |
25 | /**
26 | * Return the address of the voting machine for this scheme as registered with the given avatar.
27 | * @param avatarAddress
28 | */
29 | public async getVotingMachineAddress(avatarAddress: Address): Promise {
30 | return (await this._getSchemeParameters(avatarAddress)).votingMachineAddress;
31 | }
32 |
33 | /**
34 | * Return IntVoteInterfaceWrapper for this scheme as registered with the given avatar.
35 | * @param avatarAddress
36 | */
37 | public async getVotingMachine(avatarAddress: Address): Promise {
38 | const votingMachineAddress = await this.getVotingMachineAddress(avatarAddress);
39 | return this.votingMachineFactory.at(votingMachineAddress);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/proposalService.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from "bignumber.js";
2 | import { Address, Hash } from "./commonTypes";
3 | import {
4 | EntityFetcherFactory,
5 | EventFetcherFactory,
6 | TransformEventCallback,
7 | Web3EventService
8 | } from "./web3EventService";
9 | import {
10 | IntVoteInterfaceWrapper,
11 | } from "./wrappers/intVoteInterface";
12 |
13 | import { DecodedLogEntryEvent } from "web3";
14 | import {
15 | ExecuteProposalEventResult,
16 | NewProposalEventResult
17 | } from "./wrappers/iIntVoteInterface";
18 | /**
19 | * A single instance of ProposalService provides services relating to a single
20 | * type of proposal (TProposal), for example a proposal to contribute rewards to a beneficiary.
21 | * When constructing a ProposalService we pass to the constructor a `ProposalMaker`
22 | * that provides functions enabling ProposalService to do its job with respect to the given TProposal.
23 | * Note it is not scoped to a particular Avatar.
24 | *
25 | * For more information, see [Proposals](/Proposals.md#proposals).
26 | */
27 | export class ProposalService {
28 |
29 | constructor(private web3EventService: Web3EventService) {
30 |
31 | }
32 |
33 | /**
34 | * Returns an EntityFetcherFactory for fetching proposal-related events. Can take any EventFetcherFactory
35 | * whose event args supply `_proposalId`. Returns events as a promise of `TProposal`. You must supply an
36 | * `EventFetcherFactory` for fetching the events and a callback to transform `TEventArgs` to a promise of `TProposal`.
37 | * Each entity, when the associated proposal is votable and options.votingMachine is supplied,
38 | * will also contain a `votingMachine` property of type `IntVoteInterfaceWrapper`.
39 | * @type TEventArgs The type of the `args` object in the event.
40 | * @type TProposal The type of object returned as a transformation of the `args` information in each event.
41 | * @param options
42 | */
43 | public getProposalEvents(
44 | options: GetProposalEventsOptions)
45 | : EntityFetcherFactory {
46 |
47 | if (!options.transformEventCallback) {
48 | throw new Error("transformEventCallback must be supplied");
49 | }
50 |
51 | if (!options.proposalsEventFetcher) {
52 | throw new Error("proposalsEventFetcher must be supplied");
53 | }
54 |
55 | const votableOnly = !!options.votableOnly;
56 |
57 | if (votableOnly && !options.votingMachine) {
58 | throw new Error("votingMachine must be supplied when votableOnly is true");
59 | }
60 |
61 | return this.web3EventService.createEntityFetcherFactory(
62 | options.proposalsEventFetcher,
63 | async (event: DecodedLogEntryEvent)
64 | : Promise => {
65 | let entity: TProposal | (TProposal & ProposalEntity) | undefined;
66 |
67 | if (options.votingMachine) {
68 | const isVotable = await options.votingMachine.isVotable({ proposalId: event.args._proposalId });
69 |
70 | entity = await (
71 | ((!votableOnly || isVotable) ?
72 | options.transformEventCallback(event) :
73 | Promise.resolve(undefined)));
74 |
75 | if (entity && isVotable) {
76 | (entity as (TProposal & ProposalEntity)).votingMachine = options.votingMachine;
77 | }
78 | } else {
79 | entity = await options.transformEventCallback(event);
80 | }
81 | return entity;
82 | },
83 | options.baseArgFilter);
84 | }
85 |
86 | /**
87 | * Returns promise of an EntityFetcherFactory for fetching votable proposals from the
88 | * given `IntVoteInterfaceWrapper`. The proposals are returned as promises of instances
89 | * of `VotableProposal`.
90 | *
91 | * @param votingMachineAddress
92 | */
93 | public getVotableProposals(votingMachine: IntVoteInterfaceWrapper):
94 | EntityFetcherFactory {
95 |
96 | return this.web3EventService.createEntityFetcherFactory(
97 | votingMachine.VotableProposals,
98 | (event: DecodedLogEntryEvent): Promise => {
99 | return Promise.resolve(
100 | {
101 | avatarAddress: event.args._organization,
102 | numOfChoices: event.args._numOfChoices.toNumber(),
103 | paramsHash: event.args._paramsHash,
104 | proposalId: event.args._proposalId,
105 | proposerAddress: event.args._proposer,
106 | }
107 | );
108 | });
109 | }
110 |
111 | /**
112 | * Returns promise of an EntityFetcherFactory for fetching executed proposals from the
113 | * given `IntVoteInterfaceWrapper`.
114 | * The proposals are returned as promises of instances of `ExecutedProposal`.
115 | *
116 | * @param votingMachineAddress
117 | */
118 | public getExecutedProposals(votingMachine: IntVoteInterfaceWrapper):
119 | EntityFetcherFactory {
120 |
121 | return this.web3EventService.createEntityFetcherFactory(
122 | votingMachine.ExecuteProposal,
123 | (event: DecodedLogEntryEvent): Promise => {
124 | return Promise.resolve(
125 | {
126 | decision: event.args._decision.toNumber(),
127 | proposalId: event.args._proposalId,
128 | totalReputation: event.args._totalReputation,
129 | }
130 | );
131 | });
132 | }
133 | }
134 |
135 | export interface EventHasPropertyId {
136 | _proposalId: Hash;
137 | }
138 |
139 | export interface VotableProposal {
140 | numOfChoices: number;
141 | paramsHash: Hash;
142 | proposalId: Hash;
143 | proposerAddress: Address;
144 | avatarAddress: Address;
145 | }
146 |
147 | // TODO: include avatar address?
148 | export interface ExecutedProposal {
149 | /**
150 | * the vote choice that won.
151 | */
152 | decision: number;
153 | /**
154 | * The id of the proposal that was executed.
155 | */
156 | proposalId: Hash;
157 | /**
158 | * The total reputation in the DAO at the time the proposal was executed
159 | */
160 | totalReputation: BigNumber;
161 | }
162 |
163 | export interface GetProposalEventsOptions {
164 | /**
165 | * Event fetcher to use to get or watch the event that supplies `TEventArgs`.
166 | */
167 | proposalsEventFetcher: EventFetcherFactory;
168 | /**
169 | * Returns Promise of `TProposal` given `TEventArgs` for the event. Return of `undefined` will be ignored, not
170 | * passed-on to the caller.
171 | */
172 | transformEventCallback: TransformEventCallback;
173 | /**
174 | * Optional to filter events on the given filter, like `{ _avatar: [anAddress] }`.
175 | * This will be merged with any filter that the caller provides when creating the EntityFetcher.
176 | */
177 | baseArgFilter?: any;
178 | /**
179 | * True to only return votable proposals. Default is false.
180 | */
181 | votableOnly?: boolean;
182 | /**
183 | * Used to determine whether proposals are votable.
184 | * This is only required when votableOnly is set to `true`.
185 | */
186 | votingMachine?: IntVoteInterfaceWrapper;
187 | }
188 |
189 | export interface ProposalEntity {
190 | votingMachine: IntVoteInterfaceWrapper;
191 | }
192 |
--------------------------------------------------------------------------------
/lib/pubSubEventService.ts:
--------------------------------------------------------------------------------
1 | import * as PubSub from "pubsub-js";
2 | import { fnVoid } from "./commonTypes";
3 | import { LoggingService } from "./loggingService";
4 | import { UtilsInternal } from "./utilsInternal";
5 |
6 | /**
7 | * A Pub/Sub event system that enables you to subscribe to various events published by Arc.js.
8 | * For more information, see [Pub/Sub Events](/Events.md#pubsubevents).
9 | */
10 | export class PubSubEventService {
11 |
12 | /**
13 | * Send the given payload to subscribers of the given topic.
14 | * @param topic See [subscribe](PubSubEventService.md#subscribe)
15 | * @param payload Sent in the subscription callback.
16 | * @returns True if there are any subscribers
17 | */
18 | public static publish(topic: string, payload: any): boolean {
19 | LoggingService.debug(`PubSubEventService: publishing ${topic}`);
20 | return PubSub.publish(topic, payload);
21 | }
22 |
23 | /**
24 | * Subscribe to the given topic or array of topics.
25 | * @param topics Identifies the event(s) to which you wish to subscribe
26 | * @param callback The function to call when the requested events are published
27 | * @returns An interface with `.unsubscribe()`. Be sure to call it!
28 | */
29 | public static subscribe(topics: string | Array, callback: EventSubscriptionCallback): IEventSubscription {
30 | return Array.isArray(topics) ?
31 | PubSubEventService.aggregate(topics, callback) :
32 | new EventSubscription(PubSub.subscribe(topics, callback));
33 | }
34 |
35 | /**
36 | * Remove all subscriptions
37 | */
38 | public static clearAllSubscriptions(): void {
39 | PubSub.clearAllSubscriptions();
40 | }
41 |
42 | /**
43 | * Unsubscribes after optional timeout.
44 | * When passed a token, removes a specific subscription,
45 | * when passed a callback, removes all subscriptions for that callback,
46 | * when passed a topic, removes all subscriptions for the topic hierarchy.
47 | *
48 | * @param key - A token, function or topic to unsubscribe.
49 | * @param milliseconds number of milliseconds to timeout.
50 | * Default is -1 which means not to timeout at all.
51 | */
52 | public static unsubscribe(
53 | key: EventSubscriptionKey,
54 | milliseconds: number = -1): Promise {
55 | // timeout to allow lingering events to be handled before unsubscribing
56 | if (milliseconds === -1) {
57 | PubSub.unsubscribe(key);
58 | return Promise.resolve();
59 | }
60 | // timeout to allow lingering events to be handled before unsubscribing
61 | return new Promise((resolve: fnVoid): void => {
62 | setTimeout(() => {
63 | PubSub.unsubscribe(key);
64 | resolve();
65 | }, milliseconds);
66 | });
67 | }
68 |
69 | /**
70 | * Return whether topic is specified by matchTemplates.
71 | *
72 | * Examples:
73 | *
74 | * matchTemplates: ["foo"]
75 | * topic: "foo.bar"
76 | * result: true
77 | *
78 | * matchTemplates: ["foo.bar"]
79 | * topic: "foo"
80 | * result: false
81 | *
82 | * Or a wildcard:
83 | *
84 | * matchTemplates: "*"
85 | * topic: "foo"
86 | * result: true
87 | *
88 | * @param matchTemplates
89 | * @param topic
90 | */
91 | public static isTopicSpecifiedBy(
92 | matchTemplates: Array | string,
93 | topic: string): boolean {
94 |
95 | if (!topic) { return false; }
96 | if (!matchTemplates) { return false; }
97 |
98 | if ((typeof matchTemplates === "string") && (matchTemplates === "*")) { return true; }
99 |
100 | matchTemplates = UtilsInternal.ensureArray(matchTemplates);
101 |
102 | const topicWords = topic.split(".");
103 |
104 | for (const template of matchTemplates) {
105 |
106 | if (!template) { continue; }
107 | if (template === topic) { return true; }
108 | if (template.length > topic.length) { continue; }
109 | if (template[0] === ".") { continue; }
110 |
111 | const templateWords = template.split(".");
112 |
113 | if (templateWords.length > topicWords.length) { continue; }
114 |
115 | let matches = false;
116 |
117 | for (let i = 0; i < templateWords.length; ++i) {
118 | const templateWord = templateWords[i];
119 | const topicWord = topicWords[i];
120 | if ((templateWord === "*") || (templateWord === topicWord)) { matches = true; } else { matches = false; break; }
121 | }
122 |
123 | if (!matches) { continue; }
124 |
125 | // else matches
126 | return true;
127 | }
128 |
129 | return false;
130 | }
131 |
132 | /**
133 | * Subscribe to multiple topics with the single given callback.
134 | * @param topics topic or collection of topics
135 | * @param callback Callback to handle them all
136 | * @returns An interface with `.unsubscribe()`. Be sure to call it!
137 | */
138 | private static aggregate(
139 | topics: Array,
140 | callback: EventSubscriptionCallback): IEventSubscription {
141 |
142 | return new SubscriptionCollection(topics, callback);
143 | }
144 | }
145 |
146 | /**
147 | * Creates a collection of subscriptions to which one can unsubscribe all at once.
148 | */
149 | export class SubscriptionCollection implements IEventSubscription {
150 |
151 | /**
152 | * Collection of values returned by `subscribe`, or the token, or the handler function
153 | */
154 | private subscriptions: Set;
155 |
156 | constructor(topics?: string | Array, callback?: EventSubscriptionCallback) {
157 | this.subscriptions = new Set();
158 | if (topics) {
159 | if (!callback) { throw new Error("SubscriptionCollection: callback is not set"); }
160 | this.subscribe(topics, callback);
161 | }
162 | }
163 |
164 | /**
165 | * Subscribe a single callback to a set of events
166 | * @param topics
167 | * @param callback
168 | */
169 | public subscribe(topics: string | Array, callback: EventSubscriptionCallback): void {
170 |
171 | topics = UtilsInternal.ensureArray(topics);
172 |
173 | topics.forEach((topic: string) => {
174 | const subscriptionKey = PubSub.subscribe(topic, callback);
175 | this.subscriptions.add(new EventSubscription(subscriptionKey));
176 | });
177 | }
178 |
179 | /**
180 | * Unsubscribe from all of the events
181 | * @param milliseconds number of milliseconds to timeout.
182 | * Default is -1 which means not to timeout at all.
183 | */
184 | public unsubscribe(milliseconds: number = -1): Promise {
185 | const promises = new Array>();
186 | this.subscriptions.forEach((s: EventSubscription) => {
187 | promises.push(s.unsubscribe.call(s, milliseconds));
188 | });
189 |
190 | return Promise.all(promises).then(() => {
191 | this.subscriptions.clear();
192 | });
193 | }
194 | }
195 |
196 | export type EventSubscriptionCallback = (topic: string, payload: any) => any;
197 | export type EventSubscriptionKey = string | EventSubscriptionCallback;
198 |
199 | export interface IEventSubscription {
200 | unsubscribe(milliseconds?: number): Promise;
201 | }
202 |
203 | export class EventSubscription implements IEventSubscription {
204 | public constructor(private key: EventSubscriptionKey) {
205 | }
206 |
207 | /**
208 | * Unsubscribes after optional timeout.
209 | * @param milliseconds number of milliseconds to timeout.
210 | * Default is -1 which means not to timeout at all.
211 | */
212 | public unsubscribe(milliseconds: number = -1): Promise {
213 | if (milliseconds === -1) {
214 | PubSub.unsubscribe(this.key);
215 | return Promise.resolve();
216 | }
217 | // timeout to allow lingering events to be handled before unsubscribing
218 | return new Promise((resolve: fnVoid): void => {
219 | setTimeout(() => {
220 | PubSub.unsubscribe(this.key);
221 | resolve();
222 | }, milliseconds);
223 | });
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/lib/schemeWrapperBase.ts:
--------------------------------------------------------------------------------
1 | import { Address, DefaultSchemePermissions, SchemePermissions } from "./commonTypes";
2 | import { ContractWrapperBase } from "./contractWrapperBase";
3 | import { ControllerService } from "./controllerService";
4 | import { ISchemeWrapper } from "./iContractWrapperBase";
5 |
6 | /**
7 | * Abstract base class for all Arc scheme contract wrapper classes. A scheme is defined as an Arc
8 | * contract that can be registered with and can thus interact with a DAO controller.
9 | */
10 | export abstract class SchemeWrapperBase extends ContractWrapperBase implements ISchemeWrapper {
11 | /**
12 | * Minimum permissions required by the scheme
13 | */
14 | public getDefaultPermissions(): SchemePermissions {
15 | return DefaultSchemePermissions.MinimumPermissions as number;
16 | }
17 |
18 | /**
19 | * Returns the scheme permissions.
20 | * @param avatarAddress
21 | */
22 | public getSchemePermissions(avatarAddress: Address): Promise {
23 | return Promise.resolve(this.getDefaultPermissions());
24 | }
25 |
26 | /**
27 | * Returns this scheme's permissions.
28 | * @param avatarAddress
29 | */
30 | protected async _getSchemePermissions(avatarAddress: Address): Promise {
31 | const controllerService = new ControllerService(avatarAddress);
32 | const controller = await controllerService.getController();
33 | const permissions = await controller.getSchemePermissions(this.address, avatarAddress) as string;
34 |
35 | return SchemePermissions.fromString(permissions);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/scripts/createGenesisDao.ts:
--------------------------------------------------------------------------------
1 | import { Web3 } from "web3";
2 | import { DAO, InitializeArcJs } from "../index";
3 |
4 | /* tslint:disable:no-console */
5 | /* tslint:disable:max-line-length */
6 |
7 | interface FounderSpec {
8 | /**
9 | * Founders' address
10 | */
11 | address: string;
12 | /**
13 | * string | number token amount to be awarded to each founder, in GEN
14 | */
15 | tokens: string | number;
16 | /**
17 | * string | number reputation amount to be awarded to each founder,
18 | * in units of the Genesis Reputation system.
19 | */
20 | reputation: string | number;
21 | }
22 |
23 | /**
24 | * Migration callback
25 | */
26 | export class GenesisDaoCreator {
27 |
28 | constructor(
29 | private web3: Web3) {
30 | }
31 |
32 | public async run(): Promise {
33 |
34 | const spec = {
35 | founders: [
36 | {
37 | address: "0xb0c908140fe6fd6fbd4990a5c2e35ca6dc12bfb2",
38 | reputation: "1000",
39 | tokens: "1000",
40 | },
41 | {
42 | address: "0x9c7f9f45a22ad3d667a5439f72b563df3aa70aae",
43 | reputation: "1000",
44 | tokens: "1000",
45 | },
46 | {
47 | address: "0xa2a064b3b22fc892dfb71923a6d844b953aa247c",
48 | reputation: "1000",
49 | tokens: "1000",
50 | },
51 | {
52 | address: "0xdeeaa92e025ca7fe34679b0b92cd4ffa162c8de8",
53 | reputation: "1000",
54 | tokens: "1000",
55 | },
56 | {
57 | address: "0x81cfdaf70273745a291a7cf9af801a4cffa87a95",
58 | reputation: "1000",
59 | tokens: "1000",
60 | },
61 | {
62 | address: "0x8ec400484deb5330bcd0bc005c13a557c5247727",
63 | reputation: "1000",
64 | tokens: "1000",
65 | },
66 | ],
67 | name: "Genesis Test",
68 | schemes: [
69 | {
70 | name: "SchemeRegistrar",
71 | votingMachineParams: {
72 | votingMachineName: "AbsoluteVote",
73 | },
74 | },
75 | {
76 | name: "GlobalConstraintRegistrar",
77 | votingMachineParams: {
78 | votingMachineName: "AbsoluteVote",
79 | },
80 | },
81 | {
82 | name: "UpgradeScheme",
83 | votingMachineParams: {
84 | votingMachineName: "AbsoluteVote",
85 | },
86 | },
87 | {
88 | name: "ContributionReward",
89 | votingMachineParams: {
90 | votingMachineName: "GenesisProtocol",
91 | },
92 | },
93 | ],
94 | tokenName: "Genesis Test",
95 | tokenSymbol: "GDT",
96 | };
97 |
98 | await InitializeArcJs();
99 |
100 | spec.founders = spec.founders.map((f: FounderSpec) => {
101 | return {
102 | address: f.address,
103 | reputation: this.web3.toWei(f.reputation),
104 | tokens: this.web3.toWei(f.tokens),
105 | };
106 | });
107 |
108 | console.log(`Genesis Test DAO with ${spec.founders.length} founders...`);
109 |
110 | const dao = await DAO.new(spec);
111 |
112 | console.log(`new DAO created at: ${dao.avatar.address}`);
113 | console.log(`native token: ${dao.token.address}`);
114 |
115 | return Promise.resolve();
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/lib/test/wrappers/testWrapper.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { DefaultSchemePermissions, Hash, SchemePermissions } from "../../commonTypes";
3 | import { ContractWrapperBase } from "../../contractWrapperBase";
4 | import { ContractWrapperFactory } from "../../contractWrapperFactory";
5 | import { ArcTransactionDataResult, IContractWrapperFactory } from "../../iContractWrapperBase";
6 | import { TxGeneratingFunctionOptions } from "../../transactionService";
7 | import { Web3EventService } from "../../web3EventService";
8 | import { AbsoluteVoteParams } from "../../wrappers/absoluteVote";
9 |
10 | export class TestWrapperWrapper extends ContractWrapperBase {
11 |
12 | public name: string = "AbsoluteVote";
13 | public friendlyName: string = "Test Wrapper";
14 | public factory: IContractWrapperFactory = TestWrapperFactory;
15 |
16 | public foo(): string {
17 | return "bar";
18 | }
19 |
20 | public aMethod(): string {
21 | return "abc";
22 | }
23 |
24 | public setParameters(
25 | params: AbsoluteVoteParams & TxGeneratingFunctionOptions): Promise> {
26 | params = Object.assign({},
27 | {
28 | ownerVote: true,
29 | votePerc: 50,
30 | },
31 | params);
32 |
33 | return super._setParameters(
34 | "AbsoluteVote.setParameters",
35 | params.txEventContext,
36 | params.votePerc,
37 | params.ownerVote
38 | );
39 | }
40 |
41 | public getDefaultPermissions(): SchemePermissions {
42 | return DefaultSchemePermissions.MinimumPermissions as number;
43 | }
44 | }
45 |
46 | export const TestWrapperFactory =
47 | new ContractWrapperFactory("AbsoluteVote", TestWrapperWrapper, new Web3EventService());
48 |
--------------------------------------------------------------------------------
/lib/uSchemeWrapperBase.ts:
--------------------------------------------------------------------------------
1 | import { Address, Hash } from "./commonTypes";
2 | import { ControllerService } from "./controllerService";
3 | import {
4 | ArcTransactionDataResult,
5 | IUniversalSchemeWrapper,
6 | StandardSchemeParams,
7 | } from "./iContractWrapperBase";
8 | import { SchemeWrapperBase } from "./schemeWrapperBase";
9 | import { TxEventContext } from "./transactionService";
10 |
11 | /**
12 | * Abstract base class for all Arc universal scheme contract wrapper classes. A universal scheme
13 | * is defined as an Arc scheme (see `SchemeWrapperBase`) that follows the pattern of registering
14 | * operating parameters with the DAO's controller, thus enabling the contract to be reused across DAOs.
15 | */
16 | export abstract class USchemeWrapperBase extends SchemeWrapperBase {
17 |
18 | /**
19 | * Given a hash, returns the associated parameters as an object.
20 | * @param paramsHash
21 | */
22 | public abstract getParameters(paramsHash: Hash): Promise;
23 |
24 | public abstract getParametersHash(params: any): Promise;
25 |
26 | public abstract setParameters(params: any): Promise>;
27 |
28 | public abstract getSchemeParameters(avatarAddress: Address): Promise;
29 |
30 | /**
31 | * Given an avatar address, returns the schemes parameters hash
32 | * @param avatarAddress
33 | */
34 | public async getSchemeParametersHash(avatarAddress: Address): Promise {
35 | const controllerService = new ControllerService(avatarAddress);
36 | const controller = await controllerService.getController();
37 | return controller.getSchemeParameters(this.address, avatarAddress);
38 | }
39 |
40 | /**
41 | * Given a hash, returns the associated parameters as an array, ordered by the order
42 | * in which the parameters appear in the contract's Parameters struct.
43 | * @param paramsHash
44 | */
45 | public getParametersArray(paramsHash: Hash): Promise> {
46 | return this.contract.parameters(paramsHash);
47 | }
48 | protected async _setParameters(
49 | functionName: string,
50 | txEventContext: TxEventContext,
51 | ...params: Array): Promise> {
52 |
53 | const parametersHash: Hash = await this.contract.getParametersHash(...params);
54 |
55 | const txResult = await this.wrapTransactionInvocation(functionName,
56 | // typically this is supposed to be an object, but here it is an array
57 | Object.assign(params, { txEventContext }),
58 | this.contract.setParameters,
59 | params);
60 |
61 | return new ArcTransactionDataResult(txResult.tx, this.contract, parametersHash);
62 | }
63 |
64 | protected async _getSchemeParameters(avatarAddress: Address): Promise {
65 | const paramsHash = await this.getSchemeParametersHash(avatarAddress);
66 | return this.getParameters(paramsHash);
67 | }
68 |
69 | protected _getParametersHash(...params: Array): Promise {
70 | return this.contract.getParametersHash(...params);
71 | }
72 |
73 | protected validateStandardSchemeParams(params: StandardSchemeParams): void {
74 | if (!params.voteParametersHash) {
75 | throw new Error(`voteParametersHash is not defined`);
76 | }
77 | if (!params.votingMachineAddress) {
78 | throw new Error(`votingMachineAddress is not defined`);
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/utilsInternal.ts:
--------------------------------------------------------------------------------
1 | import { promisify } from "es6-promisify";
2 | import { BlockWithoutTransactionData, FilterResult } from "web3";
3 | import { Address, fnVoid, Hash } from "./commonTypes";
4 | import { Utils, Web3 } from "./utils";
5 |
6 | /**
7 | * Utils not meant to be exported to the public
8 | */
9 | export class UtilsInternal {
10 |
11 | public static sleep(milliseconds: number): Promise {
12 | return new Promise((resolve: fnVoid): any => setTimeout(resolve, milliseconds));
13 | }
14 |
15 | public static ensureArray(arr: Array | T): Array {
16 | if (!Array.isArray(arr)) {
17 | arr = [arr];
18 | }
19 | return arr;
20 | }
21 |
22 | /**
23 | * Returns the last mined block in the chain.
24 | */
25 | public static async lastBlock(): Promise {
26 | const web3 = await Utils.getWeb3();
27 | return promisify((callback: any): any => web3.eth.getBlock("latest", callback))() as any;
28 | }
29 |
30 | /**
31 | * Returns the date of the last mined block in the chain.
32 | */
33 | public static async lastBlockDate(): Promise {
34 | const web3 = await Utils.getWeb3();
35 | let block;
36 | do {
37 | block = await promisify((callback: any): any =>
38 | web3.eth.getBlock("latest", callback))() as BlockWithoutTransactionData;
39 | }
40 | while (!block);
41 |
42 | return new Date(block.timestamp * 1000);
43 | }
44 |
45 | /**
46 | * Returns the last mined block in the chain.
47 | */
48 | public static async lastBlockNumber(): Promise {
49 | const web3 = await Utils.getWeb3();
50 | return promisify(web3.eth.getBlockNumber)();
51 | }
52 |
53 | /**
54 | * For environments that don't allow synchronous functions
55 | * @param filter
56 | */
57 | public static stopWatchingAsync(filter: FilterResult): Promise {
58 | return promisify((callback: any): any => filter.stopWatching(callback))();
59 | }
60 |
61 | public static getRandomNumber(): number {
62 | return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
63 | }
64 |
65 | public static getWeb3Sync(): Web3 {
66 | return (Utils as any).web3;
67 | }
68 |
69 | public static isNullAddress(address: Address): boolean {
70 | return !address || !Number.parseInt(address, 16);
71 | }
72 |
73 | public static isNullHash(hash: Hash): boolean {
74 | return !hash || !Number.parseInt(hash, 16);
75 | }
76 |
77 | /**
78 | * Returns promise of the maximum gasLimit that we dare to ever use, given the
79 | * current state of the chain.
80 | */
81 | public static async computeMaxGasLimit(): Promise {
82 | const web3 = await Utils.getWeb3();
83 | return promisify((callback: any) => web3.eth.getBlock("latest", false, callback))()
84 | .then((block: any) => {
85 | return block.gasLimit - 100000;
86 | });
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/lib/wrappers/absoluteVote.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { Address, Hash } from "../commonTypes";
3 |
4 | import { ContractWrapperFactory } from "../contractWrapperFactory";
5 | import {
6 | ArcTransactionDataResult,
7 | ArcTransactionProposalResult,
8 | ArcTransactionResult,
9 | DecodedLogEntryEvent,
10 | IContractWrapperFactory,
11 | IVotingMachineWrapper
12 | } from "../iContractWrapperBase";
13 | import { ProposalService, VotableProposal } from "../proposalService";
14 | import { TransactionService, TxGeneratingFunctionOptions } from "../transactionService";
15 | import { EntityFetcherFactory, EventFetcherFactory, Web3EventService } from "../web3EventService";
16 | import {
17 | NewProposalEventResult,
18 | OwnerVoteOptions,
19 | ProposalIdOption,
20 | ProposeOptions,
21 | VoteOptions,
22 | VoteWithSpecifiedAmountsOptions
23 | } from "./iIntVoteInterface";
24 |
25 | import { BigNumber } from "bignumber.js";
26 | import { IntVoteInterfaceWrapper } from "./intVoteInterface";
27 |
28 | export class AbsoluteVoteWrapper extends IntVoteInterfaceWrapper
29 | implements IVotingMachineWrapper {
30 |
31 | public name: string = "AbsoluteVote";
32 | public friendlyName: string = "Absolute Vote";
33 | public factory: IContractWrapperFactory = AbsoluteVoteFactory;
34 |
35 | /**
36 | * Events
37 | */
38 | public AVVoteProposal: EventFetcherFactory;
39 | public RefreshReputation: EventFetcherFactory;
40 |
41 | /**
42 | * EntityFetcherFactory for votable proposals.
43 | * @param avatarAddress
44 | */
45 | public get VotableAbsoluteVoteProposals():
46 | EntityFetcherFactory {
47 |
48 | const proposalService = new ProposalService(this.web3EventService);
49 |
50 | return proposalService.getProposalEvents({
51 | proposalsEventFetcher: this.NewProposal,
52 | transformEventCallback: async (event: DecodedLogEntryEvent): Promise => {
53 | return {
54 | avatarAddress: event.args._organization,
55 | numOfChoices: event.args._numOfChoices.toNumber(),
56 | paramsHash: event.args._paramsHash,
57 | proposalId: event.args._proposalId,
58 | proposerAddress: event.args._proposer,
59 | };
60 | },
61 | votableOnly: true,
62 | votingMachine: this,
63 | });
64 | }
65 |
66 | public getParametersHash(params: AbsoluteVoteParams): Promise {
67 | params = Object.assign({},
68 | {
69 | ownerVote: true,
70 | votePerc: 50,
71 | },
72 | params);
73 |
74 | return this._getParametersHash(
75 | params.votePerc,
76 | params.ownerVote);
77 | }
78 |
79 | public setParameters(
80 | params: AbsoluteVoteParams & TxGeneratingFunctionOptions)
81 | : Promise> {
82 |
83 | params = Object.assign({},
84 | {
85 | ownerVote: true,
86 | votePerc: 50,
87 | },
88 | params);
89 |
90 | return super._setParameters(
91 | "AbsoluteVote.setParameters",
92 | params.txEventContext,
93 | params.votePerc,
94 | params.ownerVote
95 | );
96 | }
97 |
98 | public async getParameters(paramsHash: Hash): Promise {
99 | const params = await this.getParametersArray(paramsHash);
100 | return {
101 | ownerVote: params[1],
102 | votePerc: params[0].toNumber(),
103 | };
104 | }
105 |
106 | public async propose(options: ProposeOptions & TxGeneratingFunctionOptions): Promise {
107 | const functionName = "AbsoluteVote.propose";
108 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
109 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
110 | return super.propose(Object.assign(options, { txEventContext: eventContext }));
111 | }
112 |
113 | public async vote(options: VoteOptions & TxGeneratingFunctionOptions): Promise {
114 | const functionName = "AbsoluteVote.vote";
115 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
116 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
117 | return super.vote(Object.assign(options, { txEventContext: eventContext }));
118 | }
119 |
120 | public async voteWithSpecifiedAmounts(
121 | options: VoteWithSpecifiedAmountsOptions & TxGeneratingFunctionOptions): Promise {
122 | const functionName = "AbsoluteVote.voteWithSpecifiedAmounts";
123 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
124 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
125 | return super.voteWithSpecifiedAmounts(Object.assign(options, { txEventContext: eventContext }));
126 | }
127 | public async execute(options: ProposalIdOption & TxGeneratingFunctionOptions): Promise {
128 | const functionName = "AbsoluteVote.execute";
129 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
130 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
131 | return super.execute(Object.assign(options, { txEventContext: eventContext }));
132 | }
133 | public async cancelProposal(options: ProposalIdOption & TxGeneratingFunctionOptions): Promise {
134 | const functionName = "AbsoluteVote.execute";
135 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
136 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
137 | return super.cancelProposal(Object.assign(options, { txEventContext: eventContext }));
138 | }
139 | public async ownerVote(options: OwnerVoteOptions & TxGeneratingFunctionOptions): Promise {
140 | const functionName = "AbsoluteVote.execute";
141 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
142 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
143 | return super.ownerVote(Object.assign(options, { txEventContext: eventContext }));
144 | }
145 | public async cancelVote(options: ProposalIdOption & TxGeneratingFunctionOptions): Promise {
146 | const functionName = "AbsoluteVote.execute";
147 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
148 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
149 | return super.cancelVote(Object.assign(options, { txEventContext: eventContext }));
150 | }
151 |
152 | protected hydrated(): void {
153 | super.hydrated();
154 | /* tslint:disable:max-line-length */
155 | this.AVVoteProposal = this.createEventFetcherFactory(this.contract.AVVoteProposal);
156 | this.RefreshReputation = this.createEventFetcherFactory(this.contract.RefreshReputation);
157 | /* tslint:enable:max-line-length */
158 | }
159 | }
160 |
161 | export const AbsoluteVoteFactory =
162 | new ContractWrapperFactory("AbsoluteVote", AbsoluteVoteWrapper, new Web3EventService());
163 |
164 | export interface AbsoluteVoteParams {
165 | ownerVote?: boolean;
166 | votePerc?: number;
167 | }
168 |
169 | export interface AbsoluteVoteParamsResult {
170 | ownerVote: boolean;
171 | votePerc: number;
172 | }
173 |
174 | export interface AVVoteProposalEventResult {
175 | /**
176 | * indexed
177 | */
178 | _proposalId: Hash;
179 | _isOwnerVote: boolean;
180 | }
181 |
182 | export interface RefreshReputationEventResult {
183 | /**
184 | * indexed
185 | */
186 | _proposalId: Hash;
187 | /**
188 | * indexed
189 | */
190 | _organization: Address;
191 | /**
192 | * indexed
193 | */
194 | _voter: Address;
195 |
196 | _reputation: BigNumber;
197 | }
198 |
--------------------------------------------------------------------------------
/lib/wrappers/commonEventInterfaces.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from "bignumber.js";
2 | import { Address, Hash } from "../commonTypes";
3 |
4 | export interface ProposalDeletedEventResult {
5 | /**
6 | * indexed
7 | */
8 | _avatar: Address;
9 | /**
10 | * indexed
11 | */
12 | _proposalId: Hash;
13 | }
14 |
15 | /**
16 | * fired by schemes
17 | */
18 | export interface ProposalExecutedEventResult {
19 | /**
20 | * indexed
21 | */
22 | _avatar: Address;
23 | _param: number;
24 | /**
25 | * indexed
26 | */
27 | _proposalId: Hash;
28 | }
29 |
30 | /**
31 | * fired by schemes
32 | */
33 | export interface SchemeProposalExecuted {
34 | avatarAddress: Address;
35 | winningVote: number;
36 | proposalId: Hash;
37 | }
38 |
39 | /**
40 | * fired by schemes
41 | */
42 | export interface SchemeProposalExecutedEventResult {
43 | /**
44 | * indexed
45 | */
46 | _avatar: Address;
47 | /**
48 | * typically the winning vote
49 | */
50 | _param: number;
51 | /**
52 | * indexed
53 | */
54 | _proposalId: Hash;
55 | }
56 |
--------------------------------------------------------------------------------
/lib/wrappers/externalLocking4Reputation.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import BigNumber from "bignumber.js";
3 | import { promisify } from "es6-promisify";
4 | import { Address } from "../commonTypes";
5 | import { ContractWrapperFactory } from "../contractWrapperFactory";
6 | import { ArcTransactionResult, IContractWrapperFactory } from "../iContractWrapperBase";
7 | import { TxGeneratingFunctionOptions } from "../transactionService";
8 | import { Utils } from "../utils";
9 | import { Web3EventService } from "../web3EventService";
10 | import { Locking4ReputationWrapper } from "./locking4Reputation";
11 |
12 | export class ExternalLocking4ReputationWrapper extends Locking4ReputationWrapper {
13 | public name: string = "ExternalLocking4Reputation";
14 | public friendlyName: string = "External Locking For Reputation";
15 | public factory: IContractWrapperFactory = ExternalLocking4ReputationFactory;
16 |
17 | public async initialize(options: ExternalLockingInitializeOptions & TxGeneratingFunctionOptions)
18 | : Promise {
19 |
20 | await super._initialize(options, false);
21 |
22 | if (!options.externalLockingContract) {
23 | throw new Error("externalLockingContract is not defined");
24 | }
25 | if (!options.getBalanceFuncSignature) {
26 | throw new Error("getBalanceFuncSignature is not defined");
27 | }
28 |
29 | this.logContractFunctionCall("ExternalLocking4Reputation.initialize", options);
30 |
31 | return this.wrapTransactionInvocation("ExternalLocking4Reputation.initialize",
32 | options,
33 | this.contract.initialize,
34 | [options.avatarAddress,
35 | options.reputationReward,
36 | options.lockingStartTime.getTime() / 1000,
37 | options.lockingEndTime.getTime() / 1000,
38 | options.redeemEnableTime.getTime() / 1000,
39 | options.externalLockingContract,
40 | options.getBalanceFuncSignature]
41 | );
42 | }
43 |
44 | public async getLockBlocker(options: ExternalLockingClaimOptions): Promise {
45 | /**
46 | * stub out lockerAddress, amount and period -- they aren't relevant to external locking validation.
47 | */
48 | const msg = await super.getLockBlocker(Object.assign({},
49 | { lockerAddress: "0x", amount: "1", period: 1 }
50 | ));
51 |
52 | if (msg) {
53 | return msg;
54 | }
55 |
56 | const alreadyLocked = await this.getAccountHasLocked(options.lockerAddress);
57 | if (alreadyLocked) {
58 | return "account has already executed a claim";
59 | }
60 |
61 | const currentAccount = (await Utils.getDefaultAccount()).toLowerCase();
62 | let lockerAddress: Address | number = options.lockerAddress;
63 |
64 | if (lockerAddress && (lockerAddress.toLowerCase() === currentAccount)) {
65 | lockerAddress = 0;
66 | }
67 |
68 | if (lockerAddress && !(await this.isRegistered(lockerAddress as Address))) {
69 | throw new Error(`account does not own any MGN tokens`);
70 | }
71 | }
72 |
73 | /**
74 | * Claim the MGN tokens and lock them. Provide `lockerAddress` to claim on their behalf,
75 | * otherwise claims on behalf of the caller.
76 | * @param options
77 | */
78 | public async lock(
79 | options: ExternalLockingClaimOptions & TxGeneratingFunctionOptions): Promise {
80 |
81 | const msg = await this.getLockBlocker(options);
82 | if (msg) {
83 | throw new Error(msg);
84 | }
85 |
86 | const currentAccount = (await Utils.getDefaultAccount()).toLowerCase();
87 | let lockerAddress: Address | number = options.lockerAddress;
88 |
89 | if (lockerAddress && (lockerAddress.toLowerCase() === currentAccount)) {
90 | lockerAddress = 0;
91 | }
92 |
93 | this.logContractFunctionCall("ExternalLocking4Reputation.claim", options);
94 |
95 | return this.wrapTransactionInvocation("ExternalLocking4Reputation.claim",
96 | options,
97 | this.contract.claim,
98 | [lockerAddress]
99 | );
100 | }
101 |
102 | /**
103 | * The caller is giving permission to the contract to allow someone else to claim
104 | * on their behalf.
105 | */
106 | public async register(): Promise {
107 |
108 | this.logContractFunctionCall("ExternalLocking4Reputation.register");
109 |
110 | return this.wrapTransactionInvocation("ExternalLocking4Reputation.register",
111 | {},
112 | this.contract.register,
113 | []
114 | );
115 | }
116 |
117 | /**
118 | * Returns promise of whether the given locker has tokens that can be activated in the given MGN token contract.
119 | * Assumes that MGN token API is: `lockedTokenBalances(address)`.
120 | *
121 | * @param lockerAddress
122 | * @param mgnTokenAddress
123 | */
124 | public async hasMgnToActivate(lockerAddress: Address): Promise {
125 |
126 | const web3 = await Utils.getWeb3();
127 |
128 | const mgnTokenAddress = await this.getExternalLockingContract();
129 |
130 | // tslint:disable
131 | const mgnToken = await web3.eth.contract(
132 | [
133 | {
134 | constant: true,
135 | inputs: [
136 | {
137 | name: "",
138 | type: "address"
139 | },
140 | ],
141 | name: "lockedTokenBalances",
142 | outputs: [
143 | {
144 | name: "",
145 | type: "uint256"
146 | },
147 | ],
148 | payable: false,
149 | stateMutability: "view",
150 | "type": "function",
151 | }
152 | ] as any
153 | ).at(mgnTokenAddress);
154 | // tslint:enable
155 |
156 | const balance = await promisify((callback: any): any =>
157 | mgnToken.lockedTokenBalances(lockerAddress, callback))() as any;
158 |
159 | return balance.gt(0);
160 | }
161 |
162 | /**
163 | * Returns promise of a boolean indicating whether the given address has registered
164 | * to have their tokens claimed for them (see `register`).
165 | * @param lockerAddress
166 | */
167 | public isRegistered(lockerAddress: Address): Promise {
168 | this.logContractFunctionCall("ExternalLocking4Reputation.registrar", { lockerAddress });
169 | return this.contract.registrar(lockerAddress);
170 | }
171 |
172 | public getExternalLockingContract(): Promise {
173 | this.logContractFunctionCall("ExternalLocking4Reputation.externalLockingContract");
174 | return this.contract.externalLockingContract();
175 | }
176 |
177 | public getGetBalanceFuncSignature(): Promise {
178 | this.logContractFunctionCall("ExternalLocking4Reputation.getBalanceFuncSignature");
179 | return this.contract.getBalanceFuncSignature();
180 | }
181 |
182 | /**
183 | * Promise of `true` if the given account has already executed a lock
184 | */
185 | public getAccountHasLocked(lockerAddress: Address): Promise {
186 | if (!lockerAddress) {
187 | throw new Error("lockerAddress is not defined");
188 | }
189 | this.logContractFunctionCall("ExternalLocking4Reputation.externalLockers");
190 | return this.contract.externalLockers(lockerAddress);
191 | }
192 |
193 | }
194 |
195 | export class ExternalLocking4ReputationType extends ContractWrapperFactory {
196 |
197 | public async deployed(): Promise {
198 | throw new Error("ExternalLocking4Reputation has not been deployed");
199 | }
200 | }
201 |
202 | export const ExternalLocking4ReputationFactory =
203 | new ExternalLocking4ReputationType(
204 | "ExternalLocking4Reputation",
205 | ExternalLocking4ReputationWrapper,
206 | new Web3EventService()) as ExternalLocking4ReputationType;
207 |
208 | export interface ExternalLockingInitializeOptions {
209 | avatarAddress: Address;
210 | externalLockingContract: Address;
211 | getBalanceFuncSignature: string;
212 | lockingEndTime: Date;
213 | lockingStartTime: Date;
214 | /**
215 | * Reputation cannot be redeemed until after this time, even if redeeming has been enabled.
216 | */
217 | redeemEnableTime: Date;
218 | reputationReward: BigNumber | string;
219 | }
220 |
221 | export interface ExternalLockingClaimOptions {
222 | lockerAddress?: Address;
223 | }
224 |
--------------------------------------------------------------------------------
/lib/wrappers/iBurnableToken.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { BigNumber } from "bignumber.js";
3 | import { Address } from "../commonTypes";
4 | import { ArcTransactionResult } from "../iContractWrapperBase";
5 | import { TxGeneratingFunctionOptions } from "../transactionService";
6 | import { EventFetcherFactory } from "../web3EventService";
7 |
8 | export interface IBurnableTokenWrapper {
9 |
10 | Burn: EventFetcherFactory;
11 |
12 | /**
13 | * Burn the given number of tokens
14 | * @param options
15 | */
16 | burn(options: BurnableTokenBurnOptions & TxGeneratingFunctionOptions): Promise;
17 | }
18 |
19 | export interface BurnableTokenBurnOptions {
20 | /**
21 | * Amount to burn
22 | */
23 | amount: BigNumber;
24 | }
25 |
26 | export interface BurnEventResult {
27 | /**
28 | * Who burnt the tokens
29 | * indexed
30 | */
31 | burner: Address;
32 | /**
33 | * Amount burnt
34 | */
35 | value: BigNumber;
36 | }
37 |
--------------------------------------------------------------------------------
/lib/wrappers/iErc827Token.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { ArcTransactionResult } from "../iContractWrapperBase";
3 | import { TxGeneratingFunctionOptions } from "../transactionService";
4 | import {
5 | StandardTokenApproveOptions,
6 | StandardTokenChangeApprovalOptions,
7 | StandardTokenTransferFromOptions,
8 | StandardTokenTransferOptions
9 | } from "./standardToken";
10 |
11 | export interface IErc827TokenWrapper {
12 |
13 | /**
14 | * Approve transfer of tokens by msg.sender (or `onBehalfOf`, if given)
15 | * from the given "spender". Then call the function specified
16 | * by `callData`, all in a single transaction.
17 | * @param options
18 | */
19 | approveAndCall(options: ApproveAndCallOptions & TxGeneratingFunctionOptions): Promise;
20 |
21 | /**
22 | * Transfer tokens from the current account to another. Then call the function specified
23 | * by `callData`, all in a single transaction.
24 | * @param options
25 | */
26 | transferAndCall(options: TransferAndCallOptions & TxGeneratingFunctionOptions): Promise;
27 |
28 | /**
29 | * Transfer tokens from one address to another. Then call the function specified
30 | * by `callData`, all in a single transaction.
31 | * @param options
32 | */
33 | transferFromAndCall(options: TransferFromAndCallOptions & TxGeneratingFunctionOptions)
34 | : Promise;
35 |
36 | /**
37 | * Increase the number of tokens approved that msg.sender (or `onBehalfOf`, if given)
38 | * may transfer from the given "spender".
39 | * Then call the function specified by `callData`, all in a single transaction.
40 | * @param options
41 | */
42 | increaseApprovalAndCall(options: ChangeApprovalAndCallOptions & TxGeneratingFunctionOptions)
43 | : Promise;
44 |
45 | /**
46 | * Decrease the number of tokens approved that msg.sender (or `onBehalfOf` if given)
47 | * may transfer from the given "spender".
48 | * Then call the function specified by `callData`, all in a single transaction.
49 | * @param options
50 | */
51 | decreaseApprovalAndCall(options: ChangeApprovalAndCallOptions & TxGeneratingFunctionOptions)
52 | : Promise;
53 | }
54 |
55 | export interface ApproveAndCallOptions extends StandardTokenApproveOptions {
56 | callData: string;
57 | }
58 |
59 | export interface TransferAndCallOptions extends StandardTokenTransferOptions {
60 | callData: string;
61 | }
62 |
63 | export interface TransferFromAndCallOptions extends StandardTokenTransferFromOptions {
64 | callData: string;
65 | }
66 |
67 | export interface ChangeApprovalAndCallOptions extends StandardTokenChangeApprovalOptions {
68 | callData: string;
69 | }
70 |
--------------------------------------------------------------------------------
/lib/wrappers/iIntVoteInterface.ts:
--------------------------------------------------------------------------------
1 | import BigNumber from "bignumber.js";
2 | import { Address, Hash } from "../commonTypes";
3 | import { ArcTransactionProposalResult, ArcTransactionResult } from "../iContractWrapperBase";
4 | import { TxGeneratingFunctionOptions } from "../transactionService";
5 | import { EventFetcherFactory } from "../web3EventService";
6 |
7 | /**
8 | * The Arc contract `IntVoteInterface`.
9 | */
10 | export interface IIntVoteInterface {
11 | NewProposal: EventFetcherFactory;
12 | CancelProposal: EventFetcherFactory;
13 | ExecuteProposal: EventFetcherFactory;
14 | VoteProposal: EventFetcherFactory;
15 | CancelVoting: EventFetcherFactory;
16 |
17 | address: Address;
18 |
19 | propose(options: ProposeOptions & TxGeneratingFunctionOptions): Promise;
20 | cancelProposal(options: ProposalIdOption & TxGeneratingFunctionOptions): Promise;
21 | ownerVote(options: OwnerVoteOptions & TxGeneratingFunctionOptions): Promise;
22 | vote(options: VoteOptions & TxGeneratingFunctionOptions): Promise;
23 | voteWithSpecifiedAmounts(
24 | options: VoteWithSpecifiedAmountsOptions & TxGeneratingFunctionOptions): Promise;
25 | cancelVote(options: ProposalIdOption & TxGeneratingFunctionOptions): Promise;
26 | getNumberOfChoices(options: ProposalIdOption): Promise;
27 | isVotable(options: ProposalIdOption): Promise;
28 | voteStatus(options: VoteStatusOptions): Promise;
29 | isAbstainAllow(): Promise;
30 | execute(options: ProposalIdOption & TxGeneratingFunctionOptions): Promise;
31 | }
32 |
33 | export interface ProposeOptions {
34 | numOfChoices: number;
35 | /**
36 | * Typically this is the avatar address, but you can pass any address here,
37 | * or null, This argument is used to link a proposal-creating scheme with an organisation.
38 | * If it is not given then it will be set to the `msg.sender`.
39 | */
40 | organizationAddress?: Address;
41 | proposerAddress?: Address;
42 | proposalParameters: Hash;
43 | }
44 |
45 | export interface OwnerVoteOptions extends ProposalIdOption {
46 | vote: number;
47 | voterAddress: Address;
48 | }
49 |
50 | export interface VoteOptions extends ProposalIdOption {
51 | vote: number;
52 | voterAddress?: Address;
53 | }
54 |
55 | export interface VoteWithSpecifiedAmountsOptions extends ProposalIdOption {
56 | reputation: BigNumber | string;
57 | vote: number;
58 | voterAddress?: Address;
59 | }
60 |
61 | export interface VoteStatusOptions extends ProposalIdOption {
62 | vote: number;
63 | }
64 |
65 | export interface ProposalIdOption {
66 | proposalId: Hash;
67 | }
68 |
69 | export interface CancelProposalEventResult {
70 | /**
71 | * indexed
72 | */
73 | _organization: Address;
74 | /**
75 | * indexed
76 | */
77 | _proposalId: Hash;
78 | }
79 |
80 | export interface CancelVotingEventResult {
81 | /**
82 | * indexed
83 | */
84 | _organization: Address;
85 | /**
86 | * indexed
87 | */
88 | _proposalId: Hash;
89 | /**
90 | * indexed
91 | */
92 | _voter: Address;
93 | }
94 |
95 | export interface NewProposalEventResult {
96 | /**
97 | * indexed
98 | */
99 | _organization: Address;
100 | _numOfChoices: BigNumber;
101 | _paramsHash: Hash;
102 | /**
103 | * indexed
104 | */
105 | _proposalId: Hash;
106 | _proposer: Address;
107 | }
108 |
109 | /**
110 | * fired by voting machines
111 | */
112 | export interface ExecuteProposalEventResult {
113 | /**
114 | * indexed
115 | */
116 | _organization: Address;
117 | /**
118 | * the vote choice that won.
119 | */
120 | _decision: BigNumber;
121 | /**
122 | * indexed
123 | */
124 | _proposalId: Hash;
125 | /**
126 | * The total reputation in the DAO at the time the proposal was executed
127 | */
128 | _totalReputation: BigNumber;
129 | }
130 |
131 | export interface VoteProposalEventResult {
132 | /**
133 | * indexed
134 | */
135 | _organization: Address;
136 | /**
137 | * indexed
138 | */
139 | _proposalId: Hash;
140 | _reputation: BigNumber;
141 | /**
142 | * The choice of vote
143 | */
144 | _vote: BigNumber;
145 | /**
146 | * indexed
147 | */
148 | _voter: Address;
149 | }
150 |
151 | export interface GetAllowedRangeOfChoicesResult {
152 | minVote: number;
153 | maxVote: number;
154 | }
155 |
--------------------------------------------------------------------------------
/lib/wrappers/lockingEth4Reputation.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import BigNumber from "bignumber.js";
3 | import { ContractWrapperFactory } from "../contractWrapperFactory";
4 | import { ArcTransactionResult, IContractWrapperFactory } from "../iContractWrapperBase";
5 | import { TxGeneratingFunctionOptions } from "../transactionService";
6 | import { Utils } from "../utils";
7 | import { Web3EventService } from "../web3EventService";
8 | import { InitializeOptions, Locking4ReputationWrapper, LockingOptions, ReleaseOptions } from "./locking4Reputation";
9 |
10 | export class LockingEth4ReputationWrapper extends Locking4ReputationWrapper {
11 | public name: string = "LockingEth4Reputation";
12 | public friendlyName: string = "Locking Eth For Reputation";
13 | public factory: IContractWrapperFactory = LockingEth4ReputationFactory;
14 |
15 | public async initialize(options: InitializeOptions & TxGeneratingFunctionOptions)
16 | : Promise {
17 |
18 | await super._initialize(options);
19 |
20 | this.logContractFunctionCall("LockingEth4Reputation.initialize", options);
21 |
22 | return this.wrapTransactionInvocation("LockingEth4Reputation.initialize",
23 | options,
24 | this.contract.initialize,
25 | [options.avatarAddress,
26 | options.reputationReward,
27 | options.lockingStartTime.getTime() / 1000,
28 | options.lockingEndTime.getTime() / 1000,
29 | options.redeemEnableTime.getTime() / 1000,
30 | options.maxLockingPeriod]
31 | );
32 | }
33 |
34 | public async release(options: ReleaseOptions & TxGeneratingFunctionOptions): Promise {
35 |
36 | await super._release(options);
37 |
38 | this.logContractFunctionCall("LockingEth4Reputation.release", options);
39 |
40 | return this.wrapTransactionInvocation("LockingEth4Reputation.release",
41 | options,
42 | this.contract.release,
43 | [options.lockerAddress, options.lockId]
44 | );
45 | }
46 |
47 | /**
48 | * Returns reason why can't lock, else null if can lock
49 | */
50 | public async getLockBlocker(options: LockingOptions): Promise {
51 |
52 | const msg = await super.getLockBlocker(options);
53 | if (msg) {
54 | return msg;
55 | }
56 |
57 | const balance = await Utils.getEthBalance(options.lockerAddress);
58 | const amount = new BigNumber(options.amount);
59 |
60 | if (balance.lt(amount)) {
61 | return "the account has insufficient balance";
62 | }
63 | return null;
64 | }
65 |
66 | public async lock(options: LockingOptions & TxGeneratingFunctionOptions): Promise {
67 |
68 | const msg = await this.getLockBlocker(options);
69 | if (msg) {
70 | throw new Error(msg);
71 | }
72 |
73 | this.logContractFunctionCall("LockingEth4Reputation.lock", options);
74 |
75 | return this.wrapTransactionInvocation("LockingEth4Reputation.lock",
76 | options,
77 | this.contract.lock,
78 | [options.period],
79 | { from: options.lockerAddress, value: options.amount }
80 | );
81 | }
82 | }
83 |
84 | export class LockingEth4ReputationType extends ContractWrapperFactory {
85 |
86 | public async deployed(): Promise {
87 | throw new Error("LockingEth4Reputation has not been deployed");
88 | }
89 | }
90 |
91 | export const LockingEth4ReputationFactory =
92 | new LockingEth4ReputationType(
93 | "LockingEth4Reputation",
94 | LockingEth4ReputationWrapper,
95 | new Web3EventService()) as LockingEth4ReputationType;
96 |
--------------------------------------------------------------------------------
/lib/wrappers/lockingToken4Reputation.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import BigNumber from "bignumber.js";
3 | import { Address, Hash } from "../commonTypes";
4 | import { ContractWrapperFactory } from "../contractWrapperFactory";
5 | import { ArcTransactionResult, IContractWrapperFactory } from "../iContractWrapperBase";
6 | import { TxGeneratingFunctionOptions } from "../transactionService";
7 | import { Utils } from "../utils";
8 | import { EventFetcherFactory, Web3EventService } from "../web3EventService";
9 | import { WrapperService } from "../wrapperService";
10 | import { InitializeOptions, Locking4ReputationWrapper, LockingOptions, ReleaseOptions } from "./locking4Reputation";
11 | import { StandardTokenFactory, StandardTokenWrapper } from "./standardToken";
12 |
13 | export class LockingToken4ReputationWrapper extends Locking4ReputationWrapper {
14 | public name: string = "LockingToken4Reputation";
15 | public friendlyName: string = "Locking Token For Reputation";
16 | public factory: IContractWrapperFactory = LockingToken4ReputationFactory;
17 |
18 | public LockToken: EventFetcherFactory;
19 |
20 | public async initialize(options: LockTokenInitializeOptions & TxGeneratingFunctionOptions)
21 | : Promise {
22 |
23 | await super._initialize(options);
24 |
25 | if (!options.priceOracleContract) {
26 | throw new Error(`priceOracleContract not supplied`);
27 | }
28 |
29 | this.logContractFunctionCall("LockingToken4Reputation.initialize", options);
30 |
31 | return this.wrapTransactionInvocation("LockingToken4Reputation.initialize",
32 | options,
33 | this.contract.initialize,
34 | [options.avatarAddress,
35 | options.reputationReward,
36 | options.lockingStartTime.getTime() / 1000,
37 | options.lockingEndTime.getTime() / 1000,
38 | options.redeemEnableTime.getTime() / 1000,
39 | options.maxLockingPeriod,
40 | options.priceOracleContract]
41 | );
42 | }
43 |
44 | public async release(options: ReleaseOptions & TxGeneratingFunctionOptions): Promise {
45 |
46 | await super._release(options);
47 |
48 | this.logContractFunctionCall("LockingToken4Reputation.release", options);
49 |
50 | return this.wrapTransactionInvocation("LockingToken4Reputation.release",
51 | options,
52 | this.contract.release,
53 | [options.lockerAddress, options.lockId]
54 | );
55 | }
56 |
57 | /**
58 | * Returns reason why can't lock, else null if can lock
59 | */
60 | public async getLockBlocker(options: TokenLockingOptions): Promise {
61 |
62 | const msg = await super.getLockBlocker(options);
63 | if (msg) {
64 | return msg;
65 | }
66 |
67 | if (!options.tokenAddress) {
68 | return "tokenAddress was not supplied";
69 | }
70 |
71 | const token = await StandardTokenFactory.at(options.tokenAddress);
72 | const balance = await Utils.getTokenBalance(options.lockerAddress, token.address);
73 | const amount = new BigNumber(options.amount);
74 |
75 | if (balance.lt(amount)) {
76 | return "the account has insufficient balance";
77 | }
78 |
79 | return null;
80 | }
81 |
82 | public async lock(options: TokenLockingOptions & TxGeneratingFunctionOptions): Promise {
83 |
84 | const msg = await this.getLockBlocker(options);
85 | if (msg) {
86 | throw new Error(msg);
87 | }
88 |
89 | this.logContractFunctionCall("LockingToken4Reputation.lock", options);
90 |
91 | return this.wrapTransactionInvocation("LockingToken4Reputation.lock",
92 | options,
93 | this.contract.lock,
94 | [options.amount, options.period, options.tokenAddress],
95 | { from: options.lockerAddress }
96 | );
97 | }
98 |
99 | public async getTokenForLock(lockingId: Hash): Promise {
100 | this.logContractFunctionCall("LockingToken4Reputation.lockedTokens");
101 | const address = await this.contract.lockedTokens(lockingId);
102 | return WrapperService.factories.StandardToken.at(address);
103 | }
104 | }
105 |
106 | export class LockingToken4ReputationType extends ContractWrapperFactory {
107 |
108 | public async deployed(): Promise {
109 | throw new Error("LockingToken4Reputation has not been deployed");
110 | }
111 | }
112 |
113 | export const LockingToken4ReputationFactory =
114 | new LockingToken4ReputationType(
115 | "LockingToken4Reputation",
116 | LockingToken4ReputationWrapper,
117 | new Web3EventService()) as LockingToken4ReputationType;
118 |
119 | export interface LockTokenInitializeOptions extends InitializeOptions {
120 | priceOracleContract: Address;
121 | }
122 |
123 | export interface LockingToken4ReputationLockEventResult {
124 | /**
125 | * indexed
126 | */
127 | _lockingId: BigNumber;
128 | /**
129 | * indexed
130 | */
131 | _token: Address;
132 | /**
133 | * number/denominator is the price of the token at the time the token is locked
134 | */
135 | _numerator: BigNumber;
136 | /**
137 | * number/denominator is the price of the token at the time the token is locked
138 | */
139 | _denominator: BigNumber;
140 | }
141 |
142 | export interface TokenLockingOptions extends LockingOptions {
143 | tokenAddress: Address;
144 | }
145 |
--------------------------------------------------------------------------------
/lib/wrappers/mintableToken.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { BigNumber } from "bignumber.js";
3 | import { Address } from "../commonTypes";
4 | import { ContractWrapperFactory } from "../contractWrapperFactory";
5 | import { ArcTransactionResult, IContractWrapperFactory } from "../iContractWrapperBase";
6 | import { LoggingService } from "../loggingService";
7 | import { TransactionService, TxGeneratingFunctionOptions } from "../transactionService";
8 | import { EventFetcherFactory, Web3EventService } from "../web3EventService";
9 | import {
10 | StandardTokenApproveOptions,
11 | StandardTokenChangeApprovalOptions,
12 | StandardTokenTransferFromOptions,
13 | StandardTokenTransferOptions,
14 | StandardTokenWrapper
15 | } from "./standardToken";
16 |
17 | export class MintableTokenWrapper extends StandardTokenWrapper {
18 | public name: string = "MintableToken";
19 | public friendlyName: string = "Mintable Token";
20 | public factory: IContractWrapperFactory = MintableTokenFactory;
21 |
22 | public Mint: EventFetcherFactory;
23 | public MintFinished: EventFetcherFactory;
24 |
25 | /**
26 | * Mint tokens to recipient
27 | * @param options
28 | */
29 | public async mint(options: MintableTokenMintOptions & TxGeneratingFunctionOptions)
30 | : Promise {
31 |
32 | if (!options.recipient) {
33 | throw new Error("recipient is not defined");
34 | }
35 |
36 | const amount = new BigNumber(options.amount);
37 |
38 | if (amount.eq(0)) {
39 | LoggingService.warn("MintableToken.mint: amount is zero. Doing nothing.");
40 | return new ArcTransactionResult(null, this.contract);
41 | }
42 |
43 | this.logContractFunctionCall("MintableToken.mint", options);
44 |
45 | return this.wrapTransactionInvocation("MintableToken.mint",
46 | options,
47 | this.contract.mint,
48 | [options.recipient, options.amount]
49 | );
50 | }
51 |
52 | /**
53 | * Terminate the ability to mint tokens
54 | * @param options
55 | */
56 | public async finishMinting(options?: TxGeneratingFunctionOptions)
57 | : Promise {
58 |
59 | this.logContractFunctionCall("MintableToken.finishMinting", options);
60 |
61 | return this.wrapTransactionInvocation("MintableToken.finishMinting",
62 | options,
63 | this.contract.finishMinting,
64 | []
65 | );
66 | }
67 |
68 | public async approve(options: StandardTokenApproveOptions & TxGeneratingFunctionOptions)
69 | : Promise {
70 | const functionName = "MintableToken.approve";
71 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
72 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
73 | return super.approve(Object.assign(options, { txEventContext: eventContext }));
74 | }
75 |
76 | public async transfer(options: StandardTokenTransferOptions & TxGeneratingFunctionOptions)
77 | : Promise {
78 | const functionName = "MintableToken.transfer";
79 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
80 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
81 | return super.transfer(Object.assign(options, { txEventContext: eventContext }));
82 | }
83 |
84 | public async transferFrom(options: StandardTokenTransferFromOptions & TxGeneratingFunctionOptions)
85 | : Promise {
86 | const functionName = "MintableToken.transferFrom";
87 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
88 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
89 | return super.transferFrom(Object.assign(options, { txEventContext: eventContext }));
90 | }
91 |
92 | public async increaseApproval(options: StandardTokenChangeApprovalOptions & TxGeneratingFunctionOptions)
93 | : Promise {
94 | const functionName = "MintableToken.increaseApproval";
95 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
96 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
97 | return super.increaseApproval(Object.assign(options, { txEventContext: eventContext }));
98 | }
99 |
100 | public async decreaseApproval(options: StandardTokenChangeApprovalOptions & TxGeneratingFunctionOptions)
101 | : Promise {
102 | const functionName = "MintableToken.decreaseApproval";
103 | const payload = TransactionService.publishKickoffEvent(functionName, options, 1);
104 | const eventContext = TransactionService.newTxEventContext(functionName, payload, options);
105 | return super.decreaseApproval(Object.assign(options, { txEventContext: eventContext }));
106 | }
107 |
108 | protected hydrated(): void {
109 | super.hydrated();
110 | /* tslint:disable:max-line-length */
111 | this.Mint = this.createEventFetcherFactory(this.contract.Mint);
112 | this.MintFinished = this.createEventFetcherFactory(this.contract.MintFinished);
113 | /* tslint:enable:max-line-length */
114 | }
115 | }
116 |
117 | /**
118 | * defined just to add good type checking
119 | */
120 | export class MintableTokenFactoryType extends ContractWrapperFactory {
121 |
122 | public async deployed(): Promise {
123 | throw new Error("MintableToken has not been deployed");
124 | }
125 | }
126 |
127 | export const MintableTokenFactory =
128 | new MintableTokenFactoryType(
129 | "MintableToken",
130 | MintableTokenWrapper,
131 | new Web3EventService()) as MintableTokenFactoryType;
132 |
133 | export interface MintableTokenMintOptions {
134 | /**
135 | * The token recipient
136 | */
137 | recipient: Address;
138 | /**
139 | * Amount to mint
140 | */
141 | amount: BigNumber | string;
142 | }
143 |
144 | export interface MintEventResult {
145 | /**
146 | * The token recipient
147 | * indexed
148 | */
149 | to: Address;
150 | /**
151 | * Amount minted
152 | */
153 | amount: BigNumber;
154 | }
155 |
156 | /* tslint:disable-next-line:no-empty-interface */
157 | export interface MintFinishedEventResult {
158 | }
159 |
--------------------------------------------------------------------------------
/lib/wrappers/redeemer.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { BigNumber } from "bignumber.js";
3 | import { Address, BinaryVoteResult, Hash } from "../commonTypes";
4 | import { ContractWrapperBase } from "../contractWrapperBase";
5 | import { ContractWrapperFactory } from "../contractWrapperFactory";
6 | import { ArcTransactionResult, IContractWrapperFactory } from "../iContractWrapperBase";
7 | import { TxGeneratingFunctionOptions } from "../transactionService";
8 | import { Web3EventService } from "../web3EventService";
9 |
10 | export class RedeemerWrapper extends ContractWrapperBase {
11 | public name: string = "Redeemer";
12 | public friendlyName: string = "Redeemer";
13 | public factory: IContractWrapperFactory = RedeemerFactory;
14 |
15 | /**
16 | * Redeems rewards for a ContributionReward proposal in a single transaction.
17 | * Calls execute on the proposal if it is not yet executed.
18 | * Redeems rewardable reputation and stake from the GenesisProtocol.
19 | * Redeem rewardable contribution proposal rewards.
20 | * @param options
21 | */
22 | public async redeem(options: RedeemerOptions & TxGeneratingFunctionOptions)
23 | : Promise {
24 |
25 | if (!options.avatarAddress) {
26 | throw new Error("avatarAddress is not defined");
27 | }
28 |
29 | if (!options.beneficiaryAddress) {
30 | throw new Error("beneficiaryAddress is not defined");
31 | }
32 |
33 | if (!options.proposalId) {
34 | throw new Error("proposalId is not defined");
35 | }
36 |
37 | this.logContractFunctionCall("Redeemer.redeem", options);
38 |
39 | return this.wrapTransactionInvocation("Redeemer.redeem",
40 | options,
41 | this.contract.redeem,
42 | [options.proposalId, options.avatarAddress, options.beneficiaryAddress]
43 | );
44 | }
45 |
46 | /**
47 | * Returns the amounts that would be redeemed if `Redeemer.redeem` were invoked right now.
48 | * @param options
49 | */
50 | public async redeemables(options: RedeemerOptions)
51 | : Promise {
52 |
53 | if (!options.avatarAddress) {
54 | throw new Error("avatarAddress is not defined");
55 | }
56 |
57 | if (!options.beneficiaryAddress) {
58 | throw new Error("beneficiaryAddress is not defined");
59 | }
60 |
61 | if (!options.proposalId) {
62 | throw new Error("proposalId is not defined");
63 | }
64 |
65 | this.logContractFunctionCall("Redeemer.redeem.call", options);
66 |
67 | const result = await this.contract.redeem.call(
68 | options.proposalId,
69 | options.avatarAddress,
70 | options.beneficiaryAddress)
71 | // correct for fake truffle promises
72 | .then((r: any): any => r)
73 | .catch((ex: Error) => {
74 | throw new Error(ex.message);
75 | });
76 |
77 | return {
78 | contributionRewardEther: result[6],
79 | contributionRewardExternalToken: result[7],
80 | contributionRewardNativeToken: result[5],
81 | contributionRewardReputation: result[4],
82 | daoStakingBountyPotentialReward: result[1][1],
83 | daoStakingBountyReward: result[1][0],
84 | proposalExecuted: result[2],
85 | proposalId: options.proposalId,
86 | proposerReputationAmount: result[0][4],
87 | stakerReputationAmount: result[0][1],
88 | stakerTokenAmount: result[0][0],
89 | voterReputationAmount: result[0][3],
90 | voterTokenAmount: result[0][2],
91 | winningVote: result[3].toNumber(),
92 | };
93 | }
94 | }
95 |
96 | /**
97 | * defined just to add good type checking
98 | */
99 | export class RedeemerFactoryType extends ContractWrapperFactory {
100 |
101 | public async new(
102 | contributionRewardAddress: Address,
103 | genesisProtocolAddress: Address): Promise {
104 | return super.new(contributionRewardAddress, genesisProtocolAddress);
105 | }
106 | }
107 |
108 | export const RedeemerFactory =
109 | new RedeemerFactoryType(
110 | "Redeemer",
111 | RedeemerWrapper,
112 | new Web3EventService()) as RedeemerFactoryType;
113 |
114 | export interface RedeeemableResult {
115 | contributionRewardEther: BigNumber;
116 | contributionRewardExternalToken: BigNumber;
117 | contributionRewardNativeToken: BigNumber;
118 | contributionRewardReputation: BigNumber;
119 | daoStakingBountyReward: BigNumber;
120 | daoStakingBountyPotentialReward: BigNumber;
121 | proposalExecuted: boolean;
122 | proposalId: Hash;
123 | proposerReputationAmount: BigNumber;
124 | stakerReputationAmount: BigNumber;
125 | stakerTokenAmount: BigNumber;
126 | voterReputationAmount: BigNumber;
127 | voterTokenAmount: BigNumber;
128 | winningVote: BinaryVoteResult;
129 | }
130 |
131 | export interface RedeemerOptions {
132 | avatarAddress: Address;
133 | beneficiaryAddress: Address;
134 | proposalId: Hash;
135 | }
136 |
--------------------------------------------------------------------------------
/lib/wrappers/reputation.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { Address } from "../commonTypes";
3 | import { ArcTransactionResult, IContractWrapperFactory } from "../iContractWrapperBase";
4 |
5 | import { BigNumber } from "bignumber.js";
6 | import { ContractWrapperBase } from "../contractWrapperBase";
7 | import { ContractWrapperFactory } from "../contractWrapperFactory";
8 | import { LoggingService } from "../loggingService";
9 | import { TxGeneratingFunctionOptions } from "../transactionService";
10 | import { EventFetcherFactory, Web3EventService } from "../web3EventService";
11 |
12 | export class ReputationWrapper extends ContractWrapperBase {
13 | public name: string = "Reputation";
14 | public friendlyName: string = "Reputation";
15 | public factory: IContractWrapperFactory = ReputationFactory;
16 |
17 | public Mint: EventFetcherFactory;
18 | public Burn: EventFetcherFactory;
19 |
20 | /**
21 | * Mint reputation to the given recipient
22 | * @param options
23 | */
24 | public async mint(options: ReputationMintOptions & TxGeneratingFunctionOptions)
25 | : Promise {
26 |
27 | if (!options.recipient) {
28 | throw new Error("recipient is not defined");
29 | }
30 |
31 | const amount = new BigNumber(options.amount);
32 |
33 | if (amount.eq(0)) {
34 | LoggingService.warn("Reputation.mint: amount is zero. Doing nothing.");
35 | return new ArcTransactionResult(null, this.contract);
36 | }
37 |
38 | this.logContractFunctionCall("Reputation.mint", options);
39 |
40 | return this.wrapTransactionInvocation("Reputation.mint",
41 | options,
42 | this.contract.mint,
43 | [options.recipient, options.amount]
44 | );
45 | }
46 |
47 | /**
48 | * Remove reputation from the given account.
49 | * @param options
50 | */
51 | public async burn(options: ReputationBurnOptions & TxGeneratingFunctionOptions)
52 | : Promise {
53 |
54 | if (!options.from) {
55 | throw new Error("'from' is not defined");
56 | }
57 |
58 | const amount = new BigNumber(options.amount);
59 |
60 | if (amount.eq(0)) {
61 | LoggingService.warn("Reputation.burn: amount is zero. Doing nothing.");
62 | return new ArcTransactionResult(null, this.contract);
63 | }
64 |
65 | this.logContractFunctionCall("Reputation.burn", options);
66 |
67 | return this.wrapTransactionInvocation("Reputation.burn",
68 | options,
69 | this.contract.burn,
70 | [options.from, options.amount]
71 | );
72 | }
73 |
74 | public getTotalSupply(): Promise {
75 | this.logContractFunctionCall("Reputation.totalSupply");
76 | return this.contract.totalSupply();
77 | }
78 |
79 | /**
80 | * Total amount of reputation at the given `blockNumber`.
81 | */
82 | public getTotalSupplyAt(blockNumber: number): Promise {
83 | this.logContractFunctionCall("Reputation.totalSupplyAt");
84 | return this.contract.totalSupply();
85 | }
86 |
87 | public getBalanceOf(accountAddress: Address): Promise {
88 |
89 | if (!accountAddress) {
90 | throw new Error("accountAddress is not defined");
91 | }
92 |
93 | this.logContractFunctionCall("Reputation.balanceOf", accountAddress);
94 |
95 | return this.contract.balanceOf(accountAddress);
96 | }
97 |
98 | /**
99 | * Queries the balance of `accountAddress` at the given `blockNumber`
100 | * @param accountAddress
101 | * @param blockNumber
102 | */
103 | public getBalanceOfAt(accountAddress: Address, blockNumber: number): Promise {
104 |
105 | if (!accountAddress) {
106 | throw new Error("accountAddress is not defined");
107 | }
108 |
109 | if (typeof (blockNumber) === "undefined") {
110 | throw new Error("blockNumber is not defined");
111 | }
112 |
113 | this.logContractFunctionCall("Reputation.balanceOfAt", { accountAddress, blockNumber });
114 |
115 | return this.contract.balanceOfAt(accountAddress, blockNumber);
116 | }
117 |
118 | protected hydrated(): void {
119 | /* tslint:disable:max-line-length */
120 | this.Mint = this.createEventFetcherFactory(this.contract.Mint);
121 | this.Burn = this.createEventFetcherFactory(this.contract.Burn);
122 | /* tslint:enable:max-line-length */
123 | }
124 | }
125 |
126 | export class ReputationFactoryType extends ContractWrapperFactory {
127 |
128 | public async deployed(): Promise {
129 | throw new Error("Reputation has not been deployed");
130 | }
131 | }
132 |
133 | export const ReputationFactory =
134 | new ReputationFactoryType(
135 | "Reputation",
136 | ReputationWrapper,
137 | new Web3EventService()) as ReputationFactoryType;
138 |
139 | export interface ReputationMintOptions {
140 | /**
141 | * The token recipient
142 | */
143 | recipient: Address;
144 | /**
145 | * Amount to mint
146 | */
147 | amount: BigNumber;
148 | }
149 |
150 | export interface ReputationBurnOptions {
151 | from: BigNumber;
152 | /**
153 | * Amount to mint
154 | */
155 | amount: BigNumber;
156 | }
157 |
158 | export interface ReputationMintEventResult {
159 | /**
160 | * The recipient of reputation
161 | * indexed
162 | */
163 | _to: Address;
164 | /**
165 | * Amount minted
166 | */
167 | _amount: BigNumber;
168 | }
169 |
170 | export interface ReputationBurnEventResult {
171 | /**
172 | * Whose reputation was burnt
173 | * indexed
174 | */
175 | _from: Address;
176 | /**
177 | * Amount burnt
178 | */
179 | _amount: BigNumber;
180 | }
181 |
--------------------------------------------------------------------------------
/lib/wrappers/tokenCapGC.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { Address, Hash } from "../commonTypes";
3 | import { ContractWrapperBase } from "../contractWrapperBase";
4 | import { ArcTransactionDataResult, IContractWrapperFactory } from "../iContractWrapperBase";
5 |
6 | import BigNumber from "bignumber.js";
7 | import { ContractWrapperFactory } from "../contractWrapperFactory";
8 | import { ControllerService } from "../controllerService";
9 | import { TxGeneratingFunctionOptions } from "../transactionService";
10 | import { Web3EventService } from "../web3EventService";
11 |
12 | export class TokenCapGCWrapper extends ContractWrapperBase {
13 | public name: string = "TokenCapGC";
14 | public friendlyName: string = "Token Cap Global Constraint";
15 | public factory: IContractWrapperFactory = TokenCapGCFactory;
16 |
17 | public getParametersHash(params: TokenCapGcParams): Promise {
18 | return this._getParametersHash(
19 | params.token,
20 | params.cap || 0
21 | );
22 | }
23 | public setParameters(
24 | params: TokenCapGcParams & TxGeneratingFunctionOptions): Promise> {
25 |
26 | if (!params.token) {
27 | throw new Error("token must be set");
28 | }
29 | const cap = new BigNumber(params.cap);
30 |
31 | if (cap.lt(0)) {
32 | throw new Error("cap must be greater than or equal to zero");
33 | }
34 |
35 | return super._setParameters(
36 | "TokenCapGC.setParameters",
37 | params.txEventContext,
38 | params.token,
39 | cap);
40 | }
41 |
42 | public async getParameters(paramsHash: Hash): Promise {
43 | const params = await this.getParametersArray(paramsHash);
44 | return {
45 | cap: params[1],
46 | token: params[0],
47 | };
48 | }
49 |
50 | public async getRegisteredParametersHash(avatarAddress: Address): Promise {
51 | const controllerService = new ControllerService(avatarAddress);
52 | const controller = await controllerService.getController();
53 | return controller.getGlobalConstraintParameters(this.address, avatarAddress);
54 | }
55 |
56 | public async getRegisteredParameters(avatarAddress: Address): Promise {
57 | const paramsHash = await this.getRegisteredParametersHash(avatarAddress);
58 | return this.getParameters(paramsHash);
59 | }
60 | }
61 |
62 | export const TokenCapGCFactory =
63 | new ContractWrapperFactory("TokenCapGC", TokenCapGCWrapper, new Web3EventService());
64 |
65 | export interface TokenCapGcParams {
66 | cap: BigNumber | string;
67 | token: Address;
68 | }
69 |
70 | export interface GetTokenCapGcParamsResult {
71 | cap: BigNumber;
72 | token: Address;
73 | }
74 |
--------------------------------------------------------------------------------
/lib/wrappers/voteInOrganizationScheme.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import { BigNumber } from "bignumber.js";
3 | import { Address, DefaultSchemePermissions, Hash, SchemePermissions } from "../commonTypes";
4 | import { ContractWrapperFactory } from "../contractWrapperFactory";
5 | import {
6 | ArcTransactionDataResult,
7 | ArcTransactionProposalResult,
8 | DecodedLogEntryEvent,
9 | IContractWrapperFactory,
10 | IUniversalSchemeWrapper,
11 | StandardSchemeParams,
12 | } from "../iContractWrapperBase";
13 | import { ProposalGeneratorBase } from "../proposalGeneratorBase";
14 | import { TxGeneratingFunctionOptions } from "../transactionService";
15 | import { EntityFetcherFactory, EventFetcherFactory, Web3EventService } from "../web3EventService";
16 | import {
17 | ProposalDeletedEventResult,
18 | SchemeProposalExecuted,
19 | SchemeProposalExecutedEventResult
20 | } from "./commonEventInterfaces";
21 |
22 | export class VoteInOrganizationSchemeWrapper extends ProposalGeneratorBase {
23 |
24 | public name: string = "VoteInOrganizationScheme";
25 | public friendlyName: string = "Vote In Organization Scheme";
26 | public factory: IContractWrapperFactory = VoteInOrganizationSchemeFactory;
27 | /**
28 | * Events
29 | */
30 |
31 | public NewVoteProposal: EventFetcherFactory;
32 | public ProposalExecuted: EventFetcherFactory;
33 | public ProposalDeleted: EventFetcherFactory;
34 | public VoteOnBehalf: EventFetcherFactory;
35 |
36 | /**
37 | * Submit a proposal to vote on a proposal in another DAO.
38 | * @param options
39 | */
40 | public async proposeVoteInOrganization(
41 | options: VoteInOrganizationProposeVoteConfig =
42 | {} as VoteInOrganizationProposeVoteConfig & TxGeneratingFunctionOptions)
43 | : Promise {
44 |
45 | if (!options.avatar) {
46 | throw new Error("avatar is not defined");
47 | }
48 |
49 | if (!options.originalVotingMachineAddress) {
50 | throw new Error("originalVotingMachineAddress is not defined");
51 | }
52 |
53 | if (!options.originalProposalId) {
54 | throw new Error("originalProposalId is not defined");
55 | }
56 |
57 | this.logContractFunctionCall("VoteInOrganizationScheme.proposeVote", options);
58 |
59 | const txResult = await this.wrapTransactionInvocation("VoteInOrganizationScheme.proposeVote",
60 | options,
61 | this.contract.proposeVote,
62 | [options.avatar,
63 | options.originalVotingMachineAddress,
64 | options.originalProposalId]
65 | );
66 |
67 | return new ArcTransactionProposalResult(txResult.tx, this.contract, await this.getVotingMachine(options.avatar));
68 | }
69 |
70 | /**
71 | * EntityFetcherFactory for votable VoteInOrganizationProposal.
72 | * @param avatarAddress
73 | */
74 | public async getVotableProposals(avatarAddress: Address):
75 | Promise> {
76 |
77 | return this.proposalService.getProposalEvents(
78 | {
79 | baseArgFilter: { _avatar: avatarAddress },
80 | proposalsEventFetcher: this.NewVoteProposal,
81 | transformEventCallback:
82 | async (event: DecodedLogEntryEvent)
83 | : Promise => {
84 | return this.getVotableProposal(event.args._avatar, event.args._proposalId);
85 | },
86 | votableOnly: true,
87 | votingMachine: await this.getVotingMachine(avatarAddress),
88 | });
89 | }
90 |
91 | /**
92 | * EntityFetcherFactory for executed proposals.
93 | * @param avatarAddress
94 | */
95 | public getExecutedProposals(avatarAddress: Address):
96 | EntityFetcherFactory {
97 |
98 | return this.proposalService.getProposalEvents(
99 | {
100 | baseArgFilter: { _avatar: avatarAddress },
101 | proposalsEventFetcher: this.ProposalExecuted,
102 | transformEventCallback:
103 | (event: DecodedLogEntryEvent): Promise => {
104 | return Promise.resolve({
105 | avatarAddress: event.args._avatar,
106 | proposalId: event.args._proposalId,
107 | winningVote: event.args._param,
108 | });
109 | },
110 | });
111 | }
112 |
113 | public async getVotableProposal(
114 | avatarAddress: Address,
115 | proposalId: Hash): Promise {
116 |
117 | const proposalParams = await this.contract.organizationsProposals(avatarAddress, proposalId);
118 | return this.convertProposalPropsArrayToObject(proposalParams, proposalId);
119 | }
120 |
121 | public getParametersHash(params: StandardSchemeParams): Promise