refactor contrats with aragonos
This commit is contained in:
4
apps/contribution/.gitignore
vendored
Normal file
4
apps/contribution/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build
|
||||
.cache
|
||||
dist
|
||||
14
apps/contribution/.ipfsignore
Normal file
14
apps/contribution/.ipfsignore
Normal file
@@ -0,0 +1,14 @@
|
||||
# Git files
|
||||
.gitignore
|
||||
|
||||
# Build files
|
||||
.cache
|
||||
node_modules
|
||||
build
|
||||
|
||||
# Lock files
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Others
|
||||
test
|
||||
162
apps/contribution/README.md
Normal file
162
apps/contribution/README.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# Aragon React Boilerplate
|
||||
|
||||
> 🕵️ [Find more boilerplates using GitHub](https://github.com/search?q=topic:aragon-boilerplate) |
|
||||
> ✨ [Official boilerplates](https://github.com/search?q=topic:aragon-boilerplate+org:aragon)
|
||||
|
||||
React boilerplate for Aragon applications.
|
||||
|
||||
This boilerplate also includes a fully working example app, complete with a background worker and a front-end in React (with Aragon UI).
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
aragon init app.aragonpm.eth react
|
||||
```
|
||||
|
||||
## Running your app
|
||||
|
||||
### Using HTTP
|
||||
|
||||
Running your app using HTTP will allow for a faster development process of your app's front-end, as it can be hot-reloaded without the need to execute `aragon run` every time a change is made.
|
||||
|
||||
- First start your app's development server running `npm run start:app`, and keep that process running. By default it will rebuild the app and reload the server when changes to the source are made.
|
||||
|
||||
- After that, you can run `npm run start:aragon:http` which will compile your app's contracts, publish the app locally and create a DAO. You will need to stop it and run it again after making changes to your smart contracts.
|
||||
|
||||
Changes to the app's background script (`app/script.js`) cannot be hot-reloaded, after making changes to the script, you will need to either restart the development server (`npm run start:app`) or rebuild the script `npm run build:script`.
|
||||
|
||||
### Using IPFS
|
||||
|
||||
Running your app using IPFS will mimic the production environment that will be used for running your app. `npm run start:aragon:ipfs` will run your app using IPFS. Whenever a change is made to any file in your front-end, a new version of the app needs to be published, so the command needs to be restarted.
|
||||
|
||||
## What's in the box?
|
||||
|
||||
### npm Scripts
|
||||
|
||||
- **start** or **start:aragon:ipfs**: Runs your app inside a DAO served from IPFS
|
||||
- **start:aragon:http**: Runs your app inside a DAO served with HTTP (hot reloading)
|
||||
- **start:app**: Starts a development server for your app
|
||||
- **compile**: Compile the smart contracts
|
||||
- **build**: Builds the front-end and background script
|
||||
- **build:app**: Builds the front-end
|
||||
- **build:script**: Builds the background script
|
||||
- **test**: Runs tests for the contracts
|
||||
- **publish:patch**: Release a patch version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:minor**: Release a minor version to aragonPM (only frontend/content changes allowed)
|
||||
- **publish:major**: Release a major version to aragonPM (frontend **and** contract changes)
|
||||
- **versions**: Check the currently installed versions of the app
|
||||
|
||||
### Libraries
|
||||
|
||||
- [**@aragon/os**](https://github.com/aragon/aragonos): Aragon interfaces
|
||||
- [**@aragon/client**](https://github.com/aragon/aragon.js/tree/master/packages/aragon-client): Wrapper for Aragon application RPC
|
||||
- [**@aragon/ui**](https://github.com/aragon/aragon-ui): Aragon UI components (in React)
|
||||
|
||||
## Publish
|
||||
|
||||
This app has 3 environments defined in `arapp.json`:
|
||||
|
||||
| Environment | Network |
|
||||
|--- |--- |
|
||||
| default | localhost |
|
||||
| staging | rinkeby |
|
||||
| production | mainnet |
|
||||
|
||||
Prerequisites:
|
||||
- ENS Registry address
|
||||
|
||||
Note: the `default` environment which points to `localhost` does not have an ENS Registry address specified because the `@aragon/cli` will default the value to `0xB9462EF3441346dBc6E49236Edbb0dF207db09B7` (the ENS Registry pre-deployed on the local development chain).
|
||||
|
||||
### Introduction to environments
|
||||
|
||||
Environments are defined in `arapp.json`, for example `staging` points to:
|
||||
- an ENS registry (`0x314159265dd8dbb310642f98f50c066173c1259b`)
|
||||
- an APM registry (`open.aragonpm.eth`)
|
||||
- an APM repository (`app`)
|
||||
- an Ethereum network (`rinkeby`)
|
||||
- an Ethereum websockets provider (`wss://rinkeby.eth.aragon.network/ws` - to **read** from the blockchain)
|
||||
|
||||
The `rinkeby` network is further defined in `truffle.js`, and has:
|
||||
- an Ethereum provider (to **write** to the blockchain):
|
||||
- an address (`https://rinkeby.infura.io`)
|
||||
- an Ethereum Account (`0xb4124cEB3451635DAcedd11767f004d8a28c6eE7`)
|
||||
(which is the first account generated from the `DEFAULT_MNEMONIC` variable, to use a different account see [here](#Using-a-different-Ethereum-account))
|
||||
|
||||
### Major version: content + contract
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:major -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (the output lives in `dist`)
|
||||
2. _compile_ the app's contract (the output lives in `build`)
|
||||
3. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
> aragon apm publish major "--environment" "staging"
|
||||
|
||||
✔ Successfully published app.open.aragonpm.eth v1.0.0:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
ℹ Transaction hash: 0x3d752db29cc106e9ff98b260a90615921eb32471425a29ead8cbb830fb224d8
|
||||
```
|
||||
|
||||
Note: the contract location is defined in `arapp.json` under `path`.
|
||||
Note: you can also deploy a major version with only frontend changes by passing `--only-content`.
|
||||
|
||||
### Minor/patch version: content only
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run publish:patch -- --environment staging
|
||||
```
|
||||
|
||||
This will:
|
||||
1. _build_ the app's frontend (which lives in `dist`)
|
||||
2. publish the app to the **staging** environment.
|
||||
|
||||
Sample output:
|
||||
```
|
||||
✔ Successfully published app.open.aragonpm.eth v1.1.1:
|
||||
ℹ Contract address: 0xE636bcA5B95e94F749F63E322a04DB59362299F1
|
||||
ℹ Content (ipfs): QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
ℹ Transaction hash: 0x57864d8efd8d439008621b494b19a3e8f876a8a46b38475f9626802f0a1403c2
|
||||
```
|
||||
|
||||
### Check published versions
|
||||
|
||||
Command:
|
||||
```
|
||||
npm run versions -- --environment staging
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
ℹ app.open.aragonpm.eth has 4 published versions
|
||||
✔ 1.0.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmR695Wu5KrHNec7pRP3kPvwYihABDAyVYdX5D5vwLgxCn
|
||||
✔ 1.1.0: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmSwjUZFpv2c2e9fLoxtgFrAsAmBN4DyQGJp4RcqQcW3z3
|
||||
✔ 1.1.1: 0xE636bcA5B95e94F749F63E322a04DB59362299F1 ipfs:QmUYv9cjyNVxCyAJGK2YXjkbzh6u4iW2ak81Z9obdefM1q
|
||||
✔ 2.0.0: 0x74CBbbC932d7C344FCd789Eba24BfD40e52980c9 ipfs:Qmadb3hzwLDKtb93fF367Vg1epkdsLZF4dhpapNYynjgZF
|
||||
```
|
||||
|
||||
### Using a different Ethereum account
|
||||
|
||||
To deploy from a different account, you can:
|
||||
- define a `~/.aragon/mnemonic.json` file
|
||||
```
|
||||
{
|
||||
"mnemonic": "explain tackle mirror kit ..."
|
||||
}
|
||||
```
|
||||
or
|
||||
- define a `~/.aragon/${network_name}_key.json` file, for example: `~/.aragon/rinkeby_key.json`
|
||||
```
|
||||
{
|
||||
"keys": [
|
||||
"a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563"
|
||||
]
|
||||
}
|
||||
```
|
||||
33
apps/contribution/arapp.json
Normal file
33
apps/contribution/arapp.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"roles": [
|
||||
{
|
||||
"name": "Add contributions",
|
||||
"id": "ADD_CONTRIBUTION_ROLE",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"name": "Manage token contract",
|
||||
"id": "MANAGE_TOKEN_CONTRACT_ROLE",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"environments": {
|
||||
"default": {
|
||||
"network": "development",
|
||||
"appName": "contribution.aragonpm.eth"
|
||||
},
|
||||
"staging": {
|
||||
"registry": "0x98df287b6c145399aaa709692c8d308357bc085d",
|
||||
"appName": "contribution.open.aragonpm.eth",
|
||||
"wsRPC": "wss://rinkeby.eth.aragon.network/ws",
|
||||
"network": "rinkeby"
|
||||
},
|
||||
"production": {
|
||||
"registry": "0x314159265dd8dbb310642f98f50c066173c1259b",
|
||||
"appName": "contribution.open.aragonpm.eth",
|
||||
"wsRPC": "wss://mainnet.eth.aragon.network/ws",
|
||||
"network": "mainnet"
|
||||
}
|
||||
},
|
||||
"path": "contracts/Contribution.sol"
|
||||
}
|
||||
139
apps/contribution/contracts/Contribution.sol
Normal file
139
apps/contribution/contracts/Contribution.sol
Normal file
@@ -0,0 +1,139 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||
import "@aragon/os/contracts/kernel/IKernel.sol";
|
||||
|
||||
interface IToken {
|
||||
//function mintFor(address contributorAccount, uint256 amount, uint256 proposalId) external;
|
||||
function mintFor(address contributorAccount, uint256 amount, uint256 contributionId) public;
|
||||
}
|
||||
|
||||
contract Contribution is AragonApp {
|
||||
bytes32 public constant ADD_CONTRIBUTION_ROLE = keccak256("ADD_CONTRIBUTION_ROLE");
|
||||
|
||||
bytes32 public constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
|
||||
bytes32 public constant TOKEN_APP_ID = 0xe04a882e7a6adf5603207d545ea49aec17e6b936c4d9eae3d74dbe482264991a;
|
||||
|
||||
struct ContributionData {
|
||||
address contributor;
|
||||
uint256 amount;
|
||||
bool claimed;
|
||||
bytes32 hashDigest;
|
||||
uint8 hashFunction;
|
||||
uint8 hashSize;
|
||||
string tokenMetadataURL;
|
||||
uint claimAfterBlock;
|
||||
bool exists;
|
||||
}
|
||||
string internal name_;
|
||||
string internal symbol_;
|
||||
|
||||
address public tokenContract;
|
||||
|
||||
mapping(uint256 => address) contributionOwner;
|
||||
mapping(address => uint256[]) ownedContributions;
|
||||
|
||||
mapping(uint256 => ContributionData) public contributions;
|
||||
uint256 public contributionsCount;
|
||||
|
||||
uint256 public blocksToWait = 0;
|
||||
|
||||
event ContributionAdded(uint256 id, address indexed contributor, uint256 amount);
|
||||
event ContributionClaimed(uint256 id, address indexed contributor, uint256 amount);
|
||||
|
||||
function initialize() public onlyInit {
|
||||
initialized();
|
||||
}
|
||||
|
||||
function name() external view returns (string) {
|
||||
return name_;
|
||||
}
|
||||
|
||||
function symbol() external view returns (string) {
|
||||
return symbol_;
|
||||
}
|
||||
|
||||
function balanceOf(address owner) public view returns (uint256) {
|
||||
require(owner != address(0));
|
||||
return ownedContributions[owner].length;
|
||||
}
|
||||
|
||||
function ownerOf(uint256 contributionId) public view returns (address) {
|
||||
require(exists(contributionId));
|
||||
return contributions[contributionId].contributor;
|
||||
}
|
||||
|
||||
function tokenOfOwnerByIndex(address contributor, uint256 index) public view returns (uint256) {
|
||||
return ownedContributions[contributor][index];
|
||||
}
|
||||
|
||||
function tokenMetadata(uint256 contributionId) public view returns (string) {
|
||||
return contributions[contributionId].tokenMetadataURL;
|
||||
}
|
||||
|
||||
function getContribution(uint256 contributionId) public view returns (uint256 id, address contributor, uint256 amount, bool claimed, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize, uint claimAfterBlock, bool exists) {
|
||||
id = contributionId;
|
||||
ContributionData storage c = contributions[id];
|
||||
return (
|
||||
id,
|
||||
c.contributor,
|
||||
c.amount,
|
||||
c.claimed,
|
||||
c.hashDigest,
|
||||
c.hashFunction,
|
||||
c.hashSize,
|
||||
c.claimAfterBlock,
|
||||
c.exists
|
||||
);
|
||||
}
|
||||
|
||||
function add(uint256 amount, address contributorAccount, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_CONTRIBUTION_ROLE) {
|
||||
//require(canPerform(msg.sender, ADD_CONTRIBUTION_ROLE, new uint256[](0)), 'nope');
|
||||
uint256 contributionId = contributionsCount + 1;
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
c.exists = true;
|
||||
c.amount = amount;
|
||||
c.claimed = false;
|
||||
c.contributor = contributorAccount;
|
||||
c.hashDigest = hashDigest;
|
||||
c.hashFunction = hashFunction;
|
||||
c.hashSize = hashSize;
|
||||
c.claimAfterBlock = block.number; // + blocksToWait;
|
||||
|
||||
contributionsCount++;
|
||||
|
||||
contributionOwner[contributionId] = contributorAccount;
|
||||
ownedContributions[contributorAccount].push(contributionId);
|
||||
|
||||
emit ContributionAdded(contributionId, contributorAccount, amount);
|
||||
}
|
||||
|
||||
function claim(uint256 contributionId) public isInitialized {
|
||||
ContributionData storage c = contributions[contributionId];
|
||||
require(c.exists, 'NOT_FOUND');
|
||||
require(!c.claimed, 'ALREADY_CLAIMED');
|
||||
require(block.number > c.claimAfterBlock, 'NOT_CLAIMABLE');
|
||||
//c.claimed = true;
|
||||
//IToken(getTokenContract()).mintFor(c.contributor, c.amount, contributionId); // somehow this does not work
|
||||
bytes4 sig = bytes4(keccak256("mintFor()"));
|
||||
address token = getTokenContract();
|
||||
//IToken token = IToken(getTokenContract());
|
||||
|
||||
//token.call(sig);
|
||||
//IToken(token).mintFor(c.contributor, c.amount, contributionId);
|
||||
IToken(token).mintFor(c.contributor, c.amount, contributionId);
|
||||
|
||||
//emit ContributionClaimed(contributionId, c.contributor, c.amount);
|
||||
}
|
||||
|
||||
function getTokenContract() public view returns (address) {
|
||||
return 0x8779fc70eeea01d00efa9044c29d3c930fdb874a;
|
||||
//IKernel k = IKernel(kernel());
|
||||
|
||||
//return k.getApp(KERNEL_APP_ADDR_NAMESPACE, TOKEN_APP_ID);
|
||||
}
|
||||
|
||||
function exists(uint256 contributionId) view public returns (bool) {
|
||||
return contributions[contributionId].exists;
|
||||
}
|
||||
}
|
||||
23
apps/contribution/contracts/misc/Migrations.sol
Normal file
23
apps/contribution/contracts/misc/Migrations.sol
Normal file
@@ -0,0 +1,23 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
uint public last_completed_migration;
|
||||
|
||||
modifier restricted() {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
function Migrations() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function setCompleted(uint completed) restricted {
|
||||
last_completed_migration = completed;
|
||||
}
|
||||
|
||||
function upgrade(address new_address) restricted {
|
||||
Migrations upgraded = Migrations(new_address);
|
||||
upgraded.setCompleted(last_completed_migration);
|
||||
}
|
||||
}
|
||||
4
apps/contribution/manifest.json
Normal file
4
apps/contribution/manifest.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Contribution",
|
||||
"description": "Kredits contribution app"
|
||||
}
|
||||
5
apps/contribution/migrations/1_initial_migration.js
Normal file
5
apps/contribution/migrations/1_initial_migration.js
Normal file
@@ -0,0 +1,5 @@
|
||||
var Migrations = artifacts.require('./Migrations.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
||||
5
apps/contribution/migrations/2_deploy_contracts.js
Normal file
5
apps/contribution/migrations/2_deploy_contracts.js
Normal file
@@ -0,0 +1,5 @@
|
||||
var Contribution = artifacts.require('Contribution.sol')
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Contribution)
|
||||
}
|
||||
21093
apps/contribution/package-lock.json
generated
Normal file
21093
apps/contribution/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
apps/contribution/package.json
Normal file
28
apps/contribution/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "app-name",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@aragon/os": "^4.1.0",
|
||||
"@aragon/cli": "^5.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
},
|
||||
"scripts": {
|
||||
"start": "npm run start:aragon:ipfs",
|
||||
"start:aragon:ipfs": "aragon run",
|
||||
"start:aragon:http": "aragon run --http localhost:8001 --http-served-from ./dist",
|
||||
"start:app": "npm run sync-assets && npm run build:script -- --no-minify && parcel serve app/index.html -p 8001 --out-dir dist/ --no-cache",
|
||||
"test": "aragon contracts test",
|
||||
"compile": "aragon contracts compile",
|
||||
"sync-assets": "copy-aragon-ui-assets -n aragon-ui ./dist",
|
||||
"build:app": "",
|
||||
"build:script": "",
|
||||
"build": "",
|
||||
"publish:patch": "aragon apm publish patch",
|
||||
"publish:minor": "aragon apm publish minor",
|
||||
"publish:major": "aragon apm publish major",
|
||||
"versions": "aragon apm versions"
|
||||
},
|
||||
"keywords": []
|
||||
}
|
||||
5
apps/contribution/test/app.js
Normal file
5
apps/contribution/test/app.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const CounterApp = artifacts.require('Contribution.sol')
|
||||
|
||||
contract('Contribution', (accounts) => {
|
||||
it('should be tested')
|
||||
})
|
||||
63
apps/contribution/truffle.js
Normal file
63
apps/contribution/truffle.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* https://github.com/aragon/aragonOS/blob/v4.0.0/truffle-config.js
|
||||
*/
|
||||
const homedir = require('homedir')
|
||||
const path = require('path')
|
||||
|
||||
const HDWalletProvider = require('truffle-hdwallet-provider')
|
||||
const HDWalletProviderPrivkey = require('truffle-hdwallet-provider-privkey')
|
||||
|
||||
const DEFAULT_MNEMONIC = 'explain tackle mirror kit van hammer degree position ginger unfair soup bonus'
|
||||
|
||||
const defaultRPC = (network) =>
|
||||
`https://${network}.infura.io`
|
||||
|
||||
const configFilePath = (filename) =>
|
||||
path.join(homedir(), `.aragon/${filename}`)
|
||||
|
||||
const mnemonic = () => {
|
||||
try {
|
||||
return require(configFilePath('mnemonic.json')).mnemonic
|
||||
} catch (e) {
|
||||
return DEFAULT_MNEMONIC
|
||||
}
|
||||
}
|
||||
|
||||
const settingsForNetwork = (network) => {
|
||||
try {
|
||||
return require(configFilePath(`${network}_key.json`))
|
||||
} catch (e) {
|
||||
return { }
|
||||
}
|
||||
}
|
||||
|
||||
// Lazily loaded provider
|
||||
const providerForNetwork = (network) => (
|
||||
() => {
|
||||
let { rpc, keys } = settingsForNetwork(network)
|
||||
rpc = rpc || defaultRPC(network)
|
||||
|
||||
if (!keys || keys.length == 0) {
|
||||
return new HDWalletProvider(mnemonic(), rpc)
|
||||
}
|
||||
|
||||
return new HDWalletProviderPrivkey(keys, rpc)
|
||||
}
|
||||
)
|
||||
module.exports = {
|
||||
networks: {
|
||||
development: {
|
||||
host: 'localhost',
|
||||
port: 8545,
|
||||
network_id: '*'
|
||||
},
|
||||
mainnet: {
|
||||
network_id: 1,
|
||||
provider: providerForNetwork('mainnet')
|
||||
},
|
||||
rinkeby: {
|
||||
network_id: 4,
|
||||
provider: providerForNetwork('rinkeby')
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user