mirror of
https://github.com/status-im/subscriptions.git
synced 2025-02-20 14:28:10 +00:00
initial embark layout subscriptions
This commit is contained in:
commit
9db2ef022d
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
.embark
|
||||
chains.json
|
||||
config/production/password
|
||||
config/livenet/password
|
||||
coverage
|
||||
dist
|
||||
node_modules
|
87
app/components/blockchain.js
Normal file
87
app/components/blockchain.js
Normal file
@ -0,0 +1,87 @@
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import SimpleStorage from 'Embark/contracts/SimpleStorage';
|
||||
import React from 'react';
|
||||
import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap';
|
||||
|
||||
class Blockchain extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
valueSet: 10,
|
||||
valueGet: "",
|
||||
logs: []
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(e) {
|
||||
this.setState({ valueSet: e.target.value });
|
||||
}
|
||||
|
||||
checkEnter(e, func) {
|
||||
if (e.key !== 'Enter') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
func.apply(this, [e]);
|
||||
}
|
||||
|
||||
setValue(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var value = parseInt(this.state.valueSet, 10);
|
||||
|
||||
SimpleStorage.methods.set(value).send();
|
||||
this._addToLog("SimpleStorage.methods.set(value).send()");
|
||||
}
|
||||
|
||||
getValue(e) {
|
||||
e.preventDefault();
|
||||
|
||||
SimpleStorage.methods.get().call().then(_value => this.setState({ valueGet: _value }));
|
||||
this._addToLog("SimpleStorage.methods.get(console.log)");
|
||||
}
|
||||
|
||||
_addToLog(txt) {
|
||||
this.state.logs.push(txt);
|
||||
this.setState({ logs: this.state.logs });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<React.Fragment>
|
||||
<h3> 1. Set the value in the blockchain</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.setValue)}>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueSet}
|
||||
onChange={(e) => this.handleChange(e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.setValue(e)}>Set Value</Button>
|
||||
<HelpBlock>Once you set the value, the transaction will need to be mined and then the value will be updated
|
||||
on the blockchain.</HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> 2. Get the current value</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<HelpBlock>current value is <span className="value">{this.state.valueGet}</span></HelpBlock>
|
||||
<Button bsStyle="primary" onClick={(e) => this.getValue(e)}>Get Value</Button>
|
||||
<HelpBlock>Click the button to get the current value. The initial value is 100.</HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> 3. Contract Calls </h3>
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
{
|
||||
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Blockchain;
|
180
app/components/ens.js
Normal file
180
app/components/ens.js
Normal file
@ -0,0 +1,180 @@
|
||||
/*global web3*/
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import React from 'react';
|
||||
import { Alert, Form, FormGroup, FormControl, Button } from 'react-bootstrap';
|
||||
|
||||
window.EmbarkJS = EmbarkJS;
|
||||
|
||||
class ENS extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
valueResolve: 'eth',
|
||||
responseResolve: null,
|
||||
isResolveError: false,
|
||||
valueLookup: '',
|
||||
responseLookup: null,
|
||||
isLookupError: false,
|
||||
valueRegister: '',
|
||||
addressRegister: '',
|
||||
responseRegister: null,
|
||||
isRegisterError: false,
|
||||
embarkLogs: []
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
EmbarkJS.onReady(() => {
|
||||
if (!web3.eth.defaultAccount) {
|
||||
this.setState({
|
||||
globalError: 'There is currently no default account. If Metamask is active, please sign in or deactivate it.'
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
addressRegister: web3.eth.defaultAccount,
|
||||
valueLookup: web3.eth.defaultAccount
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleChange(stateName, e) {
|
||||
this.setState({ [stateName]: e.target.value });
|
||||
}
|
||||
|
||||
checkEnter(e, func) {
|
||||
if (e.key !== 'Enter') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
func.apply(this, [e]);
|
||||
}
|
||||
|
||||
registerSubDomain(e) {
|
||||
e.preventDefault();
|
||||
const self = this;
|
||||
const embarkLogs = this.state.embarkLogs;
|
||||
embarkLogs.push(`EmbarkJS.Names.registerSubDomain('${this.state.valueRegister}', '${this.state.addressRegister}', console.log)`);
|
||||
this.setState({
|
||||
embarkLogs: embarkLogs
|
||||
});
|
||||
|
||||
EmbarkJS.Names.registerSubDomain(this.state.valueRegister, this.state.addressRegister, (err, transaction) => {
|
||||
const message = err ? err : `Successfully registered "${this.state.valueRegister}" with ${transaction.gasUsed} gas`;
|
||||
self.setState({
|
||||
responseRegister: message,
|
||||
isRegisterError: !!err
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
resolveName(e) {
|
||||
e.preventDefault();
|
||||
const embarkLogs = this.state.embarkLogs;
|
||||
embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueResolve}', console.log)`);
|
||||
|
||||
this.setState({
|
||||
embarkLogs: embarkLogs
|
||||
});
|
||||
EmbarkJS.Names.resolve(this.state.valueResolve, (err, result) => {
|
||||
if (err) {
|
||||
return this.setState({
|
||||
responseResolve: err.message || err,
|
||||
isResolveError: true
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
responseResolve: result,
|
||||
isResolveError: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
lookupAddress(e) {
|
||||
e.preventDefault();
|
||||
const embarkLogs = this.state.embarkLogs;
|
||||
embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueLookup}', console.log)`);
|
||||
|
||||
this.setState({
|
||||
embarkLogs: embarkLogs
|
||||
});
|
||||
EmbarkJS.Names.lookup(this.state.valueLookup, (err, result) => {
|
||||
if (err) {
|
||||
return this.setState({
|
||||
responseLookup: err.message || err,
|
||||
isLookupError: true
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
responseLookup: result,
|
||||
isLookupError: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<React.Fragment>
|
||||
{this.state.globalError && <Alert bsStyle="danger">{this.state.globalError}</Alert>}
|
||||
<h3>Resolve a name</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.resolveName)}>
|
||||
<FormGroup>
|
||||
{this.state.responseResolve &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isResolveError ? 'danger' : 'success'}>
|
||||
Resolved address: <span className="value">{this.state.responseResolve}</span>
|
||||
</Alert>}
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueResolve}
|
||||
onChange={(e) => this.handleChange('valueResolve', e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.resolveName(e)}>Resolve name</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Lookup an address</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.lookupAddress)}>
|
||||
<FormGroup>
|
||||
{this.state.responseLookup &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isLookupError ? 'danger' : 'success'}>
|
||||
Looked up domain: <span className="value">{this.state.responseLookup}</span>
|
||||
</Alert>}
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueLookup}
|
||||
onChange={(e) => this.handleChange('valueLookup', e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.lookupAddress(e)}>Lookup address</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Register subdomain</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.registerSubDomain)}>
|
||||
<FormGroup>
|
||||
{this.state.responseRegister &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isRegisterError ? 'danger' : 'success'}>
|
||||
<span className="value">{this.state.responseRegister}</span>
|
||||
</Alert>}
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueRegister}
|
||||
onChange={(e) => this.handleChange('valueRegister', e)}/>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.addressRegister}
|
||||
onChange={(e) => this.handleChange('addressRegister', e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.registerSubDomain(e)}>Register subdomain</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Embark Calls </h3>
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
{
|
||||
this.state.embarkLogs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ENS;
|
272
app/components/storage.js
Normal file
272
app/components/storage.js
Normal file
@ -0,0 +1,272 @@
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import React from 'react';
|
||||
import {Alert, Form, FormGroup, FormControl, HelpBlock, Button} from 'react-bootstrap';
|
||||
|
||||
class Storage extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
textToSave: 'hello world!',
|
||||
generatedHash: '',
|
||||
loadText: '',
|
||||
storedText: '',
|
||||
fileToUpload: null,
|
||||
fileHash: '',
|
||||
imageToDownload: '',
|
||||
url: '',
|
||||
logs: [],
|
||||
storageError: '',
|
||||
valueRegister: '',
|
||||
valueResolver: '',
|
||||
};
|
||||
}
|
||||
|
||||
handleChange(e, name) {
|
||||
this.state[name] = e.target.value;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
||||
checkEnter(e, func) {
|
||||
if (e.key !== 'Enter') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
func.apply(this, [e]);
|
||||
}
|
||||
|
||||
handleFileUpload(e) {
|
||||
this.setState({fileToUpload: [e.target]});
|
||||
}
|
||||
|
||||
addToLog(txt) {
|
||||
this.state.logs.push(txt);
|
||||
this.setState({logs: this.state.logs});
|
||||
}
|
||||
|
||||
setText(e) {
|
||||
e.preventDefault();
|
||||
|
||||
EmbarkJS.Storage.saveText(this.state.textToSave)
|
||||
.then((hash) => {
|
||||
this.setState({
|
||||
generatedHash: hash,
|
||||
loadText: hash,
|
||||
storageError: ''
|
||||
});
|
||||
this.addToLog("EmbarkJS.Storage.saveText('" + this.state.textToSave + "').then(function(hash) { })");
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err) {
|
||||
this.setState({storageError: err.message});
|
||||
console.log("Storage saveText Error => " + err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadHash(e) {
|
||||
e.preventDefault();
|
||||
|
||||
EmbarkJS.Storage.get(this.state.loadText)
|
||||
.then((content) => {
|
||||
this.setState({storedText: content, storageError: ''});
|
||||
this.addToLog("EmbarkJS.Storage.get('" + this.state.loadText + "').then(function(content) { })");
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err) {
|
||||
this.setState({storageError: err.message});
|
||||
console.log("Storage get Error => " + err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uploadFile(e) {
|
||||
e.preventDefault();
|
||||
|
||||
EmbarkJS.Storage.uploadFile(this.state.fileToUpload)
|
||||
.then((hash) => {
|
||||
this.setState({
|
||||
fileHash: hash,
|
||||
imageToDownload: hash,
|
||||
storageError: ''
|
||||
});
|
||||
this.addToLog("EmbarkJS.Storage.uploadFile(this.state.fileToUpload).then(function(hash) { })");
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err) {
|
||||
this.setState({storageError: err.message});
|
||||
console.log("Storage uploadFile Error => " + err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadFile(e) {
|
||||
let _url = EmbarkJS.Storage.getUrl(this.state.imageToDownload);
|
||||
this.setState({url: _url});
|
||||
this.addToLog("EmbarkJS.Storage.getUrl('" + this.state.imageToDownload + "')");
|
||||
}
|
||||
|
||||
ipnsRegister(e) {
|
||||
e.preventDefault();
|
||||
this.setState({ registering: true, responseRegister: false });
|
||||
this.addToLog("EmbarkJS.Storage.register(this.state.ipfsHash).then(function(hash) { })");
|
||||
EmbarkJS.Storage.register(this.state.valueRegister, (err, name) => {
|
||||
let responseRegister;
|
||||
let isRegisterError = false;
|
||||
if (err) {
|
||||
isRegisterError = true;
|
||||
responseRegister = "Name Register Error: " + (err.message || err)
|
||||
} else {
|
||||
responseRegister = name;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
registering: false,
|
||||
responseRegister,
|
||||
isRegisterError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ipnsResolve(e) {
|
||||
e.preventDefault();
|
||||
this.setState({ resolving: true, responseResolver: false });
|
||||
this.addToLog("EmbarkJS.Storage.resolve(this.state.ipnsName, function(err, path) { })");
|
||||
EmbarkJS.Storage.resolve(this.state.valueResolver, (err, path) => {
|
||||
let responseResolver;
|
||||
let isResolverError = false;
|
||||
if (err) {
|
||||
isResolverError = true;
|
||||
responseResolver = "Name Resolve Error: " + (err.message || err)
|
||||
} else {
|
||||
responseResolver = path;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
resolving: false,
|
||||
responseResolver,
|
||||
isResolverError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
isIpfs(){
|
||||
return EmbarkJS.Storage.currentProviderName === 'ipfs';
|
||||
}
|
||||
|
||||
render() {
|
||||
return <React.Fragment>
|
||||
{
|
||||
!this.props.enabled ?
|
||||
<React.Fragment>
|
||||
<Alert bsStyle="warning">The node you are using does not support IPFS. Please ensure <a
|
||||
href="https://github.com/ipfs/js-ipfs-api#cors" target="_blank">CORS</a> is setup for the IPFS
|
||||
node.</Alert>
|
||||
</React.Fragment> : ''
|
||||
}
|
||||
{
|
||||
this.state.storageError !== '' ?
|
||||
<Alert bsStyle="danger">{this.state.storageError}</Alert>
|
||||
: ''
|
||||
}
|
||||
<h3>Save text to storage</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.setText)}>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.textToSave}
|
||||
onChange={e => this.handleChange(e, 'textToSave')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.setText(e)}>Save Text</Button>
|
||||
<HelpBlock>generated Hash: <span className="textHash">{this.state.generatedHash}</span></HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Load text from storage given an hash</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.loadHash)}>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
value={this.state.loadText}
|
||||
onChange={e => this.handleChange(e, 'loadText')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.loadHash(e)}>Load</Button>
|
||||
<HelpBlock>result: <span className="textHash">{this.state.storedText}</span></HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Upload file to storage</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="file"
|
||||
onChange={(e) => this.handleFileUpload(e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.uploadFile(e)}>Upload</Button>
|
||||
<HelpBlock>generated hash: <span className="fileHash">{this.state.fileHash}</span></HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Get file or image from storage</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.loadFile)}>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
value={this.state.imageToDownload}
|
||||
onChange={e => this.handleChange(e, 'imageToDownload')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.loadFile(e)}>Download</Button>
|
||||
<HelpBlock>file available at: <span><a href={this.state.url}
|
||||
target="_blank">{this.state.url}</a></span></HelpBlock>
|
||||
<HelpBlock><img src={this.state.url}/></HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
{!this.isIpfs() && <Alert bsStyle="warning">The 2 functions below are only available with IPFS</Alert>}
|
||||
|
||||
<h3>Register to IPNS</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.ipnsRegister)}>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
value={this.state.valueRegister}
|
||||
onChange={e => this.handleChange(e, 'valueRegister')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.ipnsRegister(e)}>
|
||||
{this.state.registering ? 'Registering...' : 'Register' }
|
||||
</Button>
|
||||
<HelpBlock>It will take around 1 minute</HelpBlock>
|
||||
{this.state.responseRegister &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isRegisterError ? 'danger' : 'success'}>
|
||||
<span className="value">{this.state.responseRegister}</span>
|
||||
</Alert>}
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Resolve name</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.ipnsResolve)}>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
value={this.state.valueResolver}
|
||||
onChange={e => this.handleChange(e, 'valueResolver')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.ipnsResolve(e)}>
|
||||
{this.state.resolving ? 'Resolving...' : 'Resolve' }
|
||||
</Button>
|
||||
<HelpBlock>It will take around 1 minute</HelpBlock>
|
||||
{this.state.responseResolver &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isResolverError ? 'danger' : 'success'}>
|
||||
<span className="value">{this.state.responseResolver}</span>
|
||||
</Alert>}
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
<p>EmbarkJS.Storage.setProvider('ipfs',{'{'}server: 'localhost', port: '5001'{'}'})</p>
|
||||
{
|
||||
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>;
|
||||
}
|
||||
}
|
||||
|
||||
export default Storage;
|
126
app/components/whisper.js
Normal file
126
app/components/whisper.js
Normal file
@ -0,0 +1,126 @@
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import React from 'react';
|
||||
import {Alert, Form, FormGroup, FormControl, Button} from 'react-bootstrap';
|
||||
|
||||
class Whisper extends React.Component {
|
||||
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
listenTo: '',
|
||||
channel: '',
|
||||
message: '',
|
||||
subscribedChannels: [],
|
||||
messageList: [],
|
||||
logs: []
|
||||
};
|
||||
}
|
||||
|
||||
handleChange (e, name) {
|
||||
this.state[name] = e.target.value;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
||||
checkEnter(e, func) {
|
||||
if (e.key !== 'Enter') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
func.apply(this, [e]);
|
||||
}
|
||||
|
||||
sendMessage (e) {
|
||||
e.preventDefault();
|
||||
EmbarkJS.Messages.sendMessage({topic: this.state.channel, data: this.state.message});
|
||||
this.addToLog("EmbarkJS.Messages.sendMessage({topic: '" + this.state.channel + "', data: '" + this.state.message + "'})");
|
||||
}
|
||||
|
||||
listenToChannel (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const subscribedChannels = this.state.subscribedChannels;
|
||||
subscribedChannels.push(<span>Subscribed to <b>{this.state.listenTo}</b>. Now try sending a message</span>);
|
||||
this.setState({
|
||||
subscribedChannels
|
||||
});
|
||||
|
||||
EmbarkJS.Messages.listenTo({topic: [this.state.listenTo]}, (error, message) => {
|
||||
const messageList = this.state.messageList;
|
||||
if (error) {
|
||||
messageList.push(<span className="alert-danger">Error: {error}</span>);
|
||||
} else {
|
||||
messageList.push(<span>Channel: <b>{message.topic}</b> | Message: <b>{message.data}</b></span>);
|
||||
}
|
||||
this.setState({
|
||||
messageList
|
||||
});
|
||||
});
|
||||
|
||||
this.addToLog("EmbarkJS.Messages.listenTo({topic: ['" + this.state.listenTo + "']}).then(function(message) {})");
|
||||
}
|
||||
|
||||
addToLog (txt) {
|
||||
this.state.logs.push(txt);
|
||||
this.setState({logs: this.state.logs});
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{
|
||||
!this.props.enabled ?
|
||||
<React.Fragment>
|
||||
<Alert bsStyle="warning">The node you are using does not support Whisper</Alert>
|
||||
<Alert bsStyle="warning">The node uses an unsupported version of Whisper</Alert>
|
||||
</React.Fragment> : ''
|
||||
}
|
||||
<h3>Listen To channel</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.listenToChannel)}>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.listenTo}
|
||||
placeholder="channel"
|
||||
onChange={e => this.handleChange(e, 'listenTo')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.listenToChannel(e)}>Start Listening</Button>
|
||||
<div id="subscribeList">
|
||||
{this.state.subscribedChannels.map((item, i) => <p key={i}>{item}</p>)}
|
||||
</div>
|
||||
<p>messages received:</p>
|
||||
<div id="messagesList">
|
||||
{this.state.messageList.map((item, i) => <p key={i}>{item}</p>)}
|
||||
</div>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Send Message</h3>
|
||||
<Form inline onKeyDown={(e) => this.checkEnter(e, this.sendMessage)}>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.channel}
|
||||
placeholder="channel"
|
||||
onChange={e => this.handleChange(e, 'channel')}/>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.message}
|
||||
placeholder="message"
|
||||
onChange={e => this.handleChange(e, 'message')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.sendMessage(e)}>Send Message</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
<p>EmbarkJS.Messages.setProvider('whisper')</p>
|
||||
{
|
||||
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Whisper;
|
57
app/dapp.css
Normal file
57
app/dapp.css
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
div {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.logs {
|
||||
background-color: black;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.status-offline {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: red;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.status-online {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: mediumseagreen;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
input.form-control {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.alert-result {
|
||||
margin-left: 0;
|
||||
}
|
93
app/dapp.js
Normal file
93
app/dapp.js
Normal file
@ -0,0 +1,93 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {Tabs, Tab} from 'react-bootstrap';
|
||||
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import Blockchain from './components/blockchain';
|
||||
import Whisper from './components/whisper';
|
||||
import Storage from './components/storage';
|
||||
import ENS from './components/ens';
|
||||
|
||||
import './dapp.css';
|
||||
|
||||
class App extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSelect = this.handleSelect.bind(this);
|
||||
|
||||
this.state = {
|
||||
error: null,
|
||||
activeKey: 1,
|
||||
whisperEnabled: false,
|
||||
storageEnabled: false,
|
||||
blockchainEnabled: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
EmbarkJS.onReady((err) => {
|
||||
this.setState({blockchainEnabled: true});
|
||||
if (err) {
|
||||
// If err is not null then it means something went wrong connecting to ethereum
|
||||
// you can use this to ask the user to enable metamask for e.g
|
||||
return this.setState({error: err.message || err});
|
||||
}
|
||||
|
||||
EmbarkJS.Messages.Providers.whisper.getWhisperVersion((err, _version) => {
|
||||
if (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
this.setState({whisperEnabled: true});
|
||||
});
|
||||
|
||||
EmbarkJS.Storage.isAvailable().then((result) => {
|
||||
this.setState({storageEnabled: result});
|
||||
}).catch(() => {
|
||||
this.setState({storageEnabled: false});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_renderStatus(title, available) {
|
||||
let className = available ? 'pull-right status-online' : 'pull-right status-offline';
|
||||
return <React.Fragment>
|
||||
{title}
|
||||
<span className={className}></span>
|
||||
</React.Fragment>;
|
||||
}
|
||||
|
||||
handleSelect(key) {
|
||||
this.setState({ activeKey: key });
|
||||
}
|
||||
|
||||
render() {
|
||||
const ensEnabled = EmbarkJS.Names.currentNameSystems && EmbarkJS.Names.isAvailable();
|
||||
if (this.state.error) {
|
||||
return (<div>
|
||||
<div>Something went wrong connecting to ethereum. Please make sure you have a node running or are using metamask to connect to the ethereum network:</div>
|
||||
<div>{this.state.error}</div>
|
||||
</div>);
|
||||
}
|
||||
return (<div>
|
||||
<h3>Embark - Usage Example</h3>
|
||||
<Tabs onSelect={this.handleSelect} activeKey={this.state.activeKey} id="uncontrolled-tab-example">
|
||||
<Tab eventKey={1} title={this._renderStatus('Blockchain', this.state.blockchainEnabled)}>
|
||||
<Blockchain/>
|
||||
</Tab>
|
||||
<Tab eventKey={2} title={this._renderStatus('Decentralized Storage', this.state.storageEnabled)}>
|
||||
<Storage enabled={this.state.storageEnabled}/>
|
||||
</Tab>
|
||||
<Tab eventKey={3} title={this._renderStatus('P2P communication (Whisper)', this.state.whisperEnabled)}>
|
||||
<Whisper enabled={this.state.whisperEnabled}/>
|
||||
</Tab>
|
||||
<Tab eventKey={4} title={this._renderStatus('Naming (ENS)', ensEnabled)}>
|
||||
<ENS enabled={ensEnabled}/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<App></App>, document.getElementById('app'));
|
0
app/images/.gitkeep
Normal file
0
app/images/.gitkeep
Normal file
12
app/index.html
Normal file
12
app/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Embark - SimpleStorage Demo</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body class="container">
|
||||
<div id="app">
|
||||
</div>
|
||||
<script src="js/dapp.js"></script>
|
||||
</body>
|
||||
</html>
|
150
config/blockchain.js
Normal file
150
config/blockchain.js
Normal file
@ -0,0 +1,150 @@
|
||||
module.exports = {
|
||||
// applies to all environments
|
||||
default: {
|
||||
enabled: true,
|
||||
rpcHost: "localhost", // HTTP-RPC server listening interface (default: "localhost")
|
||||
rpcPort: 8545, // HTTP-RPC server listening port (default: 8545)
|
||||
rpcCorsDomain: { // Domains from which to accept cross origin requests (browser enforced). This can also be a comma separated list
|
||||
auto: true, // When "auto" is true, Embark will automatically set the cors to the address of the webserver
|
||||
additionalCors: [] // Additional CORS domains to add to the list. If "auto" is false, only those will be added
|
||||
},
|
||||
wsRPC: true, // Enable the WS-RPC server
|
||||
wsOrigins: { // Same thing as "rpcCorsDomain", but for WS origins
|
||||
auto: true,
|
||||
additionalCors: []
|
||||
},
|
||||
wsHost: "localhost", // WS-RPC server listening interface (default: "localhost")
|
||||
wsPort: 8546 // WS-RPC server listening port (default: 8546)
|
||||
|
||||
// Accounts to use as node accounts
|
||||
// The order here corresponds to the order of `web3.eth.getAccounts`, so the first one is the `defaultAccount`
|
||||
/*,accounts: [
|
||||
{
|
||||
nodeAccounts: true, // Accounts use for the node
|
||||
numAddresses: "1", // Number of addresses/accounts (defaults to 1)
|
||||
password: "config/development/devpassword" // Password file for the accounts
|
||||
},
|
||||
// Below are additional accounts that will count as `nodeAccounts` in the `deployment` section of your contract config
|
||||
// Those will not be unlocked in the node itself
|
||||
{
|
||||
privateKey: "your_private_key"
|
||||
},
|
||||
{
|
||||
privateKeyFile: "path/to/file", // Either a keystore or a list of keys, separated by , or ;
|
||||
password: "passwordForTheKeystore" // Needed to decrypt the keystore file
|
||||
},
|
||||
{
|
||||
mnemonic: "12 word mnemonic",
|
||||
addressIndex: "0", // Optional. The index to start getting the address
|
||||
numAddresses: "1", // Optional. The number of addresses to get
|
||||
hdpath: "m/44'/60'/0'/0/" // Optional. HD derivation path
|
||||
}
|
||||
]*/
|
||||
},
|
||||
|
||||
// default environment, merges with the settings in default
|
||||
// assumed to be the intended environment by `embark run` and `embark blockchain`
|
||||
development: {
|
||||
ethereumClientName: "geth", // Can be geth or parity (default:geth)
|
||||
//ethereumClientBin: "geth", // path to the client binary. Useful if it is not in the global PATH
|
||||
networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId
|
||||
networkId: 1337, // Network id used when networkType is custom
|
||||
isDev: true, // Uses and ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
|
||||
datadir: ".embark/development/datadir", // Data directory for the databases and keystore (Geth 1.8.15 and Parity 2.0.4 can use the same base folder, till now they does not conflict with each other)
|
||||
mineWhenNeeded: true, // Uses our custom script (if isDev is false) to mine only when needed
|
||||
nodiscover: true, // Disables the peer discovery mechanism (manual peer addition)
|
||||
maxpeers: 0, // Maximum number of network peers (network disabled if set to 0) (default: 25)
|
||||
proxy: true, // Proxy is used to present meaningful information about transactions
|
||||
targetGasLimit: 8000000, // Target gas limit sets the artificial target gas floor for the blocks to mine
|
||||
simulatorBlocktime: 0 // Specify blockTime in seconds for automatic mining. Default is 0 and no auto-mining.
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run privatenet" and/or "embark blockchain privatenet"
|
||||
privatenet: {
|
||||
networkType: "custom",
|
||||
networkId: 1337,
|
||||
isDev: false,
|
||||
datadir: ".embark/privatenet/datadir",
|
||||
// -- mineWhenNeeded --
|
||||
// This options is only valid when isDev is false.
|
||||
// Enabling this option uses our custom script to mine only when needed.
|
||||
// Embark creates a development account for you (using `geth account new`) and funds the account. This account can be used for
|
||||
// development (and even imported in to MetaMask). To enable correct usage, a password for this account must be specified
|
||||
// in the `account > password` setting below.
|
||||
// NOTE: once `mineWhenNeeded` is enabled, you must run an `embark reset` on your dApp before running
|
||||
// `embark blockchain` or `embark run` for the first time.
|
||||
mineWhenNeeded: true,
|
||||
// -- genesisBlock --
|
||||
// This option is only valid when mineWhenNeeded is true (which is only valid if isDev is false).
|
||||
// When enabled, geth uses POW to mine transactions as it would normally, instead of using POA as it does in --dev mode.
|
||||
// On the first `embark blockchain or embark run` after this option is enabled, geth will create a new chain with a
|
||||
// genesis block, which can be configured using the `genesisBlock` configuration option below.
|
||||
genesisBlock: "config/privatenet/genesis.json", // Genesis block to initiate on first creation of a development node
|
||||
nodiscover: true,
|
||||
maxpeers: 0,
|
||||
proxy: true,
|
||||
accounts: [
|
||||
{
|
||||
nodeAccounts: true,
|
||||
password: "config/privatenet/password" // Password to unlock the account
|
||||
}
|
||||
],
|
||||
targetGasLimit: 8000000,
|
||||
simulatorBlocktime: 0
|
||||
},
|
||||
|
||||
privateparitynet: {
|
||||
ethereumClientName: "parity",
|
||||
networkType: "custom",
|
||||
networkId: 1337,
|
||||
isDev: false,
|
||||
genesisBlock: "config/privatenet/genesis-parity.json", // Genesis block to initiate on first creation of a development node
|
||||
datadir: ".embark/privatenet/datadir",
|
||||
mineWhenNeeded: false,
|
||||
nodiscover: true,
|
||||
maxpeers: 0,
|
||||
proxy: true,
|
||||
accounts: [
|
||||
{
|
||||
nodeAccounts: true,
|
||||
password: "config/privatenet/password"
|
||||
}
|
||||
],
|
||||
targetGasLimit: 8000000,
|
||||
simulatorBlocktime: 0
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run testnet" and/or "embark blockchain testnet"
|
||||
testnet: {
|
||||
networkType: "testnet",
|
||||
syncMode: "light",
|
||||
accounts: [
|
||||
{
|
||||
nodeAccounts: true,
|
||||
password: "config/testnet/password"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run livenet" and/or "embark blockchain livenet"
|
||||
livenet: {
|
||||
networkType: "livenet",
|
||||
syncMode: "light",
|
||||
rpcCorsDomain: "http://localhost:8000",
|
||||
wsOrigins: "http://localhost:8000",
|
||||
accounts: [
|
||||
{
|
||||
nodeAccounts: true,
|
||||
password: "config/livenet/password"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// you can name an environment with specific settings and then specify with
|
||||
// "embark run custom_name" or "embark blockchain custom_name"
|
||||
//custom_name: {
|
||||
//}
|
||||
};
|
46
config/communication.js
Normal file
46
config/communication.js
Normal file
@ -0,0 +1,46 @@
|
||||
module.exports = {
|
||||
// default applies to all environments
|
||||
default: {
|
||||
enabled: true,
|
||||
provider: "whisper", // Communication provider. Currently, Embark only supports whisper
|
||||
available_providers: ["whisper"], // Array of available providers
|
||||
},
|
||||
|
||||
// default environment, merges with the settings in default
|
||||
// assumed to be the intended environment by `embark run`
|
||||
development: {
|
||||
connection: {
|
||||
host: "localhost", // Host of the blockchain node
|
||||
port: 8546, // Port of the blockchain node
|
||||
type: "ws" // Type of connection (ws or rpc)
|
||||
}
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run privatenet"
|
||||
privatenet: {
|
||||
},
|
||||
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run testnet"
|
||||
testnet: {
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run livenet"
|
||||
livenet: {
|
||||
},
|
||||
|
||||
// you can name an environment with specific settings and then specify with
|
||||
// "embark run custom_name"
|
||||
//custom_name: {
|
||||
//}
|
||||
// Use this section when you need a specific symmetric or private keys in whisper
|
||||
/*
|
||||
,keys: {
|
||||
symmetricKey: "your_symmetric_key",// Symmetric key for message decryption
|
||||
privateKey: "your_private_key" // Private Key to be used as a signing key and for message decryption
|
||||
}
|
||||
*/
|
||||
};
|
82
config/contracts.js
Normal file
82
config/contracts.js
Normal file
@ -0,0 +1,82 @@
|
||||
module.exports = {
|
||||
// default applies to all environments
|
||||
default: {
|
||||
// Blockchain node to deploy the contracts
|
||||
deployment: {
|
||||
host: "localhost", // Host of the blockchain node
|
||||
port: 8546, // Port of the blockchain node
|
||||
type: "ws" // Type of connection (ws or rpc),
|
||||
// Accounts to use instead of the default account to populate your wallet
|
||||
/*,accounts: [
|
||||
{
|
||||
privateKey: "your_private_key",
|
||||
balance: "5 ether" // You can set the balance of the account in the dev environment
|
||||
// Balances are in Wei, but you can specify the unit with its name
|
||||
},
|
||||
{
|
||||
privateKeyFile: "path/to/file", // Either a keystore or a list of keys, separated by , or ;
|
||||
password: "passwordForTheKeystore" // Needed to decrypt the keystore file
|
||||
},
|
||||
{
|
||||
mnemonic: "12 word mnemonic",
|
||||
addressIndex: "0", // Optionnal. The index to start getting the address
|
||||
numAddresses: "1", // Optionnal. The number of addresses to get
|
||||
hdpath: "m/44'/60'/0'/0/" // Optionnal. HD derivation path
|
||||
}
|
||||
]*/
|
||||
},
|
||||
// order of connections the dapp should connect to
|
||||
dappConnection: [
|
||||
"$WEB3", // uses pre existing web3 object if available (e.g in Mist)
|
||||
"ws://localhost:8546",
|
||||
"http://localhost:8545"
|
||||
],
|
||||
|
||||
gas: "auto",
|
||||
|
||||
// Strategy for the deployment of the contracts:
|
||||
// - implicit will try to deploy all the contracts located inside the contracts directory
|
||||
// or the directory configured for the location of the contracts. This is default one
|
||||
// when not specified
|
||||
// - explicit will only attempt to deploy the contracts that are explicity specified inside the
|
||||
// contracts section.
|
||||
//strategy: 'implicit',
|
||||
|
||||
contracts: {
|
||||
SimpleStorage: {
|
||||
fromIndex: 0,
|
||||
args: [100]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// default environment, merges with the settings in default
|
||||
// assumed to be the intended environment by `embark run`
|
||||
development: {
|
||||
dappConnection: [
|
||||
"ws://localhost:8546",
|
||||
"http://localhost:8545",
|
||||
"$WEB3" // uses pre existing web3 object if available (e.g in Mist)
|
||||
]
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run privatenet"
|
||||
privatenet: {
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run testnet"
|
||||
testnet: {
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run livenet"
|
||||
livenet: {
|
||||
},
|
||||
|
||||
// you can name an environment with specific settings and then specify with
|
||||
// "embark run custom_name" or "embark blockchain custom_name"
|
||||
//custom_name: {
|
||||
//}
|
||||
};
|
1
config/development/devpassword
Normal file
1
config/development/devpassword
Normal file
@ -0,0 +1 @@
|
||||
|
1
config/development/password
Normal file
1
config/development/password
Normal file
@ -0,0 +1 @@
|
||||
dev_password
|
39
config/namesystem.js
Normal file
39
config/namesystem.js
Normal file
@ -0,0 +1,39 @@
|
||||
module.exports = {
|
||||
// default applies to all environments
|
||||
default: {
|
||||
enabled: true,
|
||||
available_providers: ["ens"],
|
||||
provider: "ens"
|
||||
},
|
||||
|
||||
// default environment, merges with the settings in default
|
||||
// assumed to be the intended environment by `embark run`
|
||||
development: {
|
||||
register: {
|
||||
rootDomain: "eth",
|
||||
subdomains: {
|
||||
'embark': '0x1a2f3b98e434c02363f3dac3174af93c1d690914'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run privatenet"
|
||||
privatenet: {
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run testnet"
|
||||
testnet: {
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run livenet"
|
||||
livenet: {
|
||||
},
|
||||
|
||||
// you can name an environment with specific settings and then specify with
|
||||
// "embark run custom_name" or "embark blockchain custom_name"
|
||||
//custom_name: {
|
||||
//}
|
||||
};
|
23
config/pipeline.js
Normal file
23
config/pipeline.js
Normal file
@ -0,0 +1,23 @@
|
||||
// Embark has support for Flow enabled by default in its built-in webpack
|
||||
// config: type annotations will automatically be stripped out of DApp sources
|
||||
// without any additional configuration. Note that type checking is not
|
||||
// performed during builds.
|
||||
|
||||
// To enable Flow type checking refer to the preconfigured template:
|
||||
// https://github.com/embark-framework/embark-flow-template
|
||||
// A new DApp can be created from that template with:
|
||||
// embark new --template flow
|
||||
|
||||
module.exports = {
|
||||
typescript: false
|
||||
// Setting `typescript: true` in this config will disable Flow support in
|
||||
// Embark's default webpack config and enable TypeScript support: .ts and
|
||||
// .tsx sources will automatically be transpiled into JavaScript without any
|
||||
// additional configuration. Note that type checking is not performed during
|
||||
// builds.
|
||||
|
||||
// To enable TypeScript type checking refer to the preconfigured template:
|
||||
// https://github.com/embark-framework/embark-typescript-template
|
||||
// A new DApp can be created from that template with:
|
||||
// embark new --template typescript
|
||||
};
|
147
config/privatenet/genesis-parity.json
Normal file
147
config/privatenet/genesis-parity.json
Normal file
File diff suppressed because one or more lines are too long
18
config/privatenet/genesis.json
Normal file
18
config/privatenet/genesis.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"config": {
|
||||
"homesteadBlock": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"daoForkSupport": true
|
||||
},
|
||||
"nonce": "0x0000000000000042",
|
||||
"difficulty": "0x0",
|
||||
"alloc": {
|
||||
"0x3333333333333333333333333333333333333333": {"balance": "15000000000000000000"}
|
||||
},
|
||||
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase": "0x3333333333333333333333333333333333333333",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x",
|
||||
"gasLimit": "0x7a1200"
|
||||
}
|
1
config/privatenet/password
Normal file
1
config/privatenet/password
Normal file
@ -0,0 +1 @@
|
||||
dev_password
|
59
config/storage.js
Normal file
59
config/storage.js
Normal file
@ -0,0 +1,59 @@
|
||||
module.exports = {
|
||||
// default applies to all environments
|
||||
default: {
|
||||
enabled: true,
|
||||
ipfs_bin: "ipfs",
|
||||
available_providers: ["ipfs"],
|
||||
upload: {
|
||||
provider: "ipfs",
|
||||
host: "localhost",
|
||||
port: 5001
|
||||
},
|
||||
dappConnection: [
|
||||
{
|
||||
provider:"ipfs",
|
||||
host: "localhost",
|
||||
port: 5001,
|
||||
getUrl: "http://localhost:8080/ipfs/"
|
||||
}
|
||||
]
|
||||
// Configuration to start Swarm in the same terminal as `embark run`
|
||||
/*,account: {
|
||||
address: "YOUR_ACCOUNT_ADDRESS", // Address of account accessing Swarm
|
||||
password: "PATH/TO/PASSWORD/FILE" // File containing the password of the account
|
||||
},
|
||||
swarmPath: "PATH/TO/SWARM/EXECUTABLE" // Path to swarm executable (default: swarm)*/
|
||||
},
|
||||
|
||||
// default environment, merges with the settings in default
|
||||
// assumed to be the intended environment by `embark run`
|
||||
development: {
|
||||
enabled: true,
|
||||
upload: {
|
||||
provider: "ipfs",
|
||||
host: "localhost",
|
||||
port: 5001,
|
||||
getUrl: "http://localhost:8080/ipfs/"
|
||||
}
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run privatenet"
|
||||
privatenet: {
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run testnet"
|
||||
testnet: {
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run livenet"
|
||||
livenet: {
|
||||
},
|
||||
|
||||
// you can name an environment with specific settings and then specify with
|
||||
// "embark run custom_name"
|
||||
//custom_name: {
|
||||
//}
|
||||
};
|
1
config/testnet/password
Normal file
1
config/testnet/password
Normal file
@ -0,0 +1 @@
|
||||
test_password
|
6
config/webserver.js
Normal file
6
config/webserver.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
enabled: true,
|
||||
host: "localhost",
|
||||
openBrowser: true,
|
||||
port: 8000
|
||||
};
|
65
contracts/math/SafeMath.sol
Normal file
65
contracts/math/SafeMath.sol
Normal file
@ -0,0 +1,65 @@
|
||||
pragma solidity ^0.5.2;
|
||||
|
||||
/**
|
||||
* @title SafeMath
|
||||
* @dev Unsigned math operations with safety checks that revert on error
|
||||
*/
|
||||
library SafeMath {
|
||||
/**
|
||||
* @dev Multiplies two unsigned integers, reverts on overflow.
|
||||
*/
|
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
|
||||
// benefit is lost if 'b' is also tested.
|
||||
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 c = a * b;
|
||||
require(c / a == b);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
|
||||
*/
|
||||
function div(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
// Solidity only automatically asserts when dividing by 0
|
||||
require(b > 0);
|
||||
uint256 c = a / b;
|
||||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
|
||||
*/
|
||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
require(b <= a);
|
||||
uint256 c = a - b;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds two unsigned integers, reverts on overflow.
|
||||
*/
|
||||
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
uint256 c = a + b;
|
||||
require(c >= a);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
|
||||
* reverts when dividing by zero.
|
||||
*/
|
||||
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
require(b != 0);
|
||||
return a % b;
|
||||
}
|
||||
}
|
65
contracts/math/SafeMath64.sol
Normal file
65
contracts/math/SafeMath64.sol
Normal file
@ -0,0 +1,65 @@
|
||||
pragma solidity ^0.5.2;
|
||||
|
||||
/**
|
||||
* @title SafeMath
|
||||
* @dev Unsigned math operations with safety checks that revert on error
|
||||
*/
|
||||
library SafeMath64 {
|
||||
/**
|
||||
* @dev Multiplies two unsigned integers, reverts on overflow.
|
||||
*/
|
||||
function mul(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
|
||||
// benefit is lost if 'b' is also tested.
|
||||
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64 c = a * b;
|
||||
require(c / a == b);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
|
||||
*/
|
||||
function div(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
// Solidity only automatically asserts when dividing by 0
|
||||
require(b > 0);
|
||||
uint64 c = a / b;
|
||||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
|
||||
*/
|
||||
function sub(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
require(b <= a);
|
||||
uint64 c = a - b;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds two unsigned integers, reverts on overflow.
|
||||
*/
|
||||
function add(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
uint64 c = a + b;
|
||||
require(c >= a);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
|
||||
* reverts when dividing by zero.
|
||||
*/
|
||||
function mod(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
require(b != 0);
|
||||
return a % b;
|
||||
}
|
||||
}
|
65
contracts/math/SafeMath8.sol
Normal file
65
contracts/math/SafeMath8.sol
Normal file
@ -0,0 +1,65 @@
|
||||
pragma solidity ^0.5.2;
|
||||
|
||||
/**
|
||||
* @title SafeMath
|
||||
* @dev Unsigned math operations with safety checks that revert on error
|
||||
*/
|
||||
library SafeMath8 {
|
||||
/**
|
||||
* @dev Multiplies two unsigned integers, reverts on overflow.
|
||||
*/
|
||||
function mul(uint8 a, uint8 b) internal pure returns (uint8) {
|
||||
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
|
||||
// benefit is lost if 'b' is also tested.
|
||||
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 c = a * b;
|
||||
require(c / a == b);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
|
||||
*/
|
||||
function div(uint8 a, uint8 b) internal pure returns (uint8) {
|
||||
// Solidity only automatically asserts when dividing by 0
|
||||
require(b > 0);
|
||||
uint8 c = a / b;
|
||||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
|
||||
*/
|
||||
function sub(uint8 a, uint8 b) internal pure returns (uint8) {
|
||||
require(b <= a);
|
||||
uint8 c = a - b;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds two unsigned integers, reverts on overflow.
|
||||
*/
|
||||
function add(uint8 a, uint8 b) internal pure returns (uint8) {
|
||||
uint8 c = a + b;
|
||||
require(c >= a);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
|
||||
* reverts when dividing by zero.
|
||||
*/
|
||||
function mod(uint8 a, uint8 b) internal pure returns (uint8) {
|
||||
require(b != 0);
|
||||
return a % b;
|
||||
}
|
||||
}
|
18
contracts/simple_storage.sol
Normal file
18
contracts/simple_storage.sol
Normal file
@ -0,0 +1,18 @@
|
||||
pragma solidity ^0.5.3;
|
||||
|
||||
contract SimpleStorage {
|
||||
uint public storedData;
|
||||
|
||||
constructor(uint initialValue) public {
|
||||
storedData = initialValue;
|
||||
}
|
||||
|
||||
function set(uint x) public {
|
||||
storedData = x;
|
||||
}
|
||||
|
||||
function get() public view returns (uint retVal) {
|
||||
return storedData;
|
||||
}
|
||||
|
||||
}
|
154
contracts/subscription.sol
Normal file
154
contracts/subscription.sol
Normal file
@ -0,0 +1,154 @@
|
||||
pragma solidity ^0.5.3;
|
||||
|
||||
import "./math/SafeMath.sol";
|
||||
import "./math/SafeMath64.sol";
|
||||
import "./math/SafeMath8.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Payroll in multiple currencies
|
||||
*/
|
||||
contract Subscription {
|
||||
using SafeMath for uint256;
|
||||
using SafeMath64 for uint64;
|
||||
using SafeMath8 for uint8;
|
||||
|
||||
bytes32 constant public ADD_EMPLOYEE_ROLE = keccak256("ADD_EMPLOYEE_ROLE");
|
||||
bytes32 constant public TERMINATE_EMPLOYEE_ROLE = keccak256("TERMINATE_EMPLOYEE_ROLE");
|
||||
bytes32 constant public SET_EMPLOYEE_SALARY_ROLE = keccak256("SET_EMPLOYEE_SALARY_ROLE");
|
||||
bytes32 constant public ADD_ACCRUED_VALUE_ROLE = keccak256("ADD_ACCRUED_VALUE_ROLE");
|
||||
bytes32 constant public ALLOWED_TOKENS_MANAGER_ROLE = keccak256("ALLOWED_TOKENS_MANAGER_ROLE");
|
||||
bytes32 constant public CHANGE_PRICE_FEED_ROLE = keccak256("CHANGE_PRICE_FEED_ROLE");
|
||||
bytes32 constant public MODIFY_RATE_EXPIRY_ROLE = keccak256("MODIFY_RATE_EXPIRY_ROLE");
|
||||
|
||||
uint128 internal constant ONE = 10 ** 18; // 10^18 is considered 1 in the price feed to allow for decimal calculations
|
||||
uint64 internal constant MAX_UINT64 = uint64(-1);
|
||||
uint256 internal constant MAX_ACCRUED_VALUE = 2**128;
|
||||
|
||||
string private constant ERROR_NO_EMPLOYEE = "PAYROLL_NO_EMPLOYEE";
|
||||
string private constant ERROR_EMPLOYEE_DOES_NOT_MATCH = "PAYROLL_EMPLOYEE_DOES_NOT_MATCH";
|
||||
string private constant ERROR_FINANCE_NOT_CONTRACT = "PAYROLL_FINANCE_NOT_CONTRACT";
|
||||
string private constant ERROR_TOKEN_ALREADY_ALLOWED = "PAYROLL_TOKEN_ALREADY_ALLOWED";
|
||||
string private constant ERROR_ACCRUED_VALUE_TOO_BIG = "PAYROLL_ACCRUED_VALUE_TOO_BIG";
|
||||
string private constant ERROR_TOKEN_ALLOCATION_MISMATCH = "PAYROLL_TOKEN_ALLOCATION_MISMATCH";
|
||||
string private constant ERROR_NO_ALLOWED_TOKEN = "PAYROLL_NO_ALLOWED_TOKEN";
|
||||
string private constant ERROR_DISTRIBUTION_NO_COMPLETE = "PAYROLL_DISTRIBUTION_NO_COMPLETE";
|
||||
string private constant ERROR_NOTHING_PAID = "PAYROLL_NOTHING_PAID";
|
||||
string private constant ERROR_EMPLOYEE_ALREADY_EXIST = "PAYROLL_EMPLOYEE_ALREADY_EXIST";
|
||||
string private constant ERROR_EMPLOYEE_NULL_ADDRESS = "PAYROLL_EMPLOYEE_NULL_ADDRESS";
|
||||
string private constant ERROR_NO_FORWARD = "PAYROLL_NO_FORWARD";
|
||||
string private constant ERROR_FEED_NOT_CONTRACT = "PAYROLL_FEED_NOT_CONTRACT";
|
||||
string private constant ERROR_EXPIRY_TIME_TOO_SHORT = "PAYROLL_EXPIRY_TIME_TOO_SHORT";
|
||||
string private constant ERROR_EXCHANGE_RATE_ZERO = "PAYROLL_EXCHANGE_RATE_ZERO";
|
||||
string private constant ERROR_PAST_TERMINATION_DATE = "PAYROLL_PAST_TERMINATION_DATE";
|
||||
|
||||
event AddAgreement(
|
||||
bytes32 agreementId,
|
||||
address receiver,
|
||||
address payor,
|
||||
uint256 initialDenominationPerSecond,
|
||||
string description,
|
||||
uint256 startDate
|
||||
);
|
||||
|
||||
// Employees start at index 1, to allow us to use employees[0] to check for non-existent address
|
||||
// mappings with employeeIds
|
||||
uint256 public nextAgreement;
|
||||
|
||||
struct Receiver {
|
||||
address accountAddress; // unique, but can be changed over time
|
||||
mapping(address => uint8) allocation;
|
||||
}
|
||||
|
||||
struct Payor {
|
||||
address accountAddress;
|
||||
mapping(address => uint256) balances;
|
||||
}
|
||||
|
||||
struct Agreement {
|
||||
address receiver;
|
||||
address payor;
|
||||
address token; // Token to be paid in
|
||||
uint256 denominationTokenPayPerSecond; // per second in denomination token
|
||||
uint256 accruedValue;
|
||||
uint256 lastPayment;
|
||||
uint256 endDate;
|
||||
string description;
|
||||
bool terminated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Container for customer balance information written to storage.
|
||||
*
|
||||
* struct Balance {
|
||||
* principal = customer total balance with accrued interest after applying the customer's most recent balance-changing action
|
||||
* interestIndex = the total interestIndex as calculated after applying the customer's most recent balance-changing action
|
||||
* }
|
||||
*/
|
||||
struct Balance {
|
||||
uint principal;
|
||||
uint interestIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev 2-level map: customerAddress -> assetAddress -> balance for payors
|
||||
*/
|
||||
mapping(address => mapping(address => Balance)) public payorBalances;
|
||||
|
||||
|
||||
/**
|
||||
* @dev 2-level map: customerAddress -> assetAddress -> balance for receivers
|
||||
*/
|
||||
mapping(address => mapping(address => Balance)) public receiverBalances;
|
||||
|
||||
/**
|
||||
* @dev map: keccask256(...args) -> Agreement
|
||||
*/
|
||||
mapping(bytes32 => Agreement) agreements;
|
||||
|
||||
constructor() public {
|
||||
nextAgreement = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Do not pay directly into Subscription, please use `supply`.
|
||||
*/
|
||||
function() payable external {
|
||||
revert();
|
||||
}
|
||||
|
||||
function createAgreement(
|
||||
address receiver,
|
||||
address payor,
|
||||
address token,
|
||||
uint256 annualAmount,
|
||||
uint256 startDate,
|
||||
string calldata description
|
||||
)
|
||||
external
|
||||
{
|
||||
require(msg.sender == payor, "Agreement must be created by payor");
|
||||
bytes32 agreementId = keccak256(abi.encode(receiver, payor, token, annualAmount, startDate, description));
|
||||
Agreement storage agreement = agreements[agreementId];
|
||||
|
||||
agreement.receiver = receiver;
|
||||
agreement.payor = payor;
|
||||
agreement.token = token;
|
||||
agreement.denominationTokenPayPerSecond = annualAmount / 325.25 days;
|
||||
agreement.lastPayment = startDate > 0 ? startDate : now;
|
||||
agreement.endDate = MAX_UINT64;
|
||||
agreement.description = description;
|
||||
|
||||
// TODO should be payor -> receiver mapping
|
||||
|
||||
emit AddAgreement(
|
||||
agreementId,
|
||||
receiver,
|
||||
payor,
|
||||
annualAmount,
|
||||
description,
|
||||
startDate
|
||||
);
|
||||
|
||||
}
|
||||
}
|
53
contracts/token/ERC20Token.sol
Normal file
53
contracts/token/ERC20Token.sol
Normal file
@ -0,0 +1,53 @@
|
||||
pragma solidity ^0.5.3;
|
||||
|
||||
// Abstract contract for the full ERC 20 Token standard
|
||||
// https://github.com/ethereum/EIPs/issues/20
|
||||
|
||||
interface ERC20Token {
|
||||
|
||||
/**
|
||||
* @notice send `_value` token to `_to` from `msg.sender`
|
||||
* @param _to The address of the recipient
|
||||
* @param _value The amount of token to be transferred
|
||||
* @return Whether the transfer was successful or not
|
||||
*/
|
||||
function transfer(address _to, uint256 _value) external returns (bool success);
|
||||
|
||||
/**
|
||||
* @notice `msg.sender` approves `_spender` to spend `_value` tokens
|
||||
* @param _spender The address of the account able to transfer the tokens
|
||||
* @param _value The amount of tokens to be approved for transfer
|
||||
* @return Whether the approval was successful or not
|
||||
*/
|
||||
function approve(address _spender, uint256 _value) external returns (bool success);
|
||||
|
||||
/**
|
||||
* @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
|
||||
* @param _from The address of the sender
|
||||
* @param _to The address of the recipient
|
||||
* @param _value The amount of token to be transferred
|
||||
* @return Whether the transfer was successful or not
|
||||
*/
|
||||
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
|
||||
|
||||
/**
|
||||
* @param _owner The address from which the balance will be retrieved
|
||||
* @return The balance
|
||||
*/
|
||||
function balanceOf(address _owner) external view returns (uint256 balance);
|
||||
|
||||
/**
|
||||
* @param _owner The address of the account owning tokens
|
||||
* @param _spender The address of the account able to transfer the tokens
|
||||
* @return Amount of remaining tokens allowed to spent
|
||||
*/
|
||||
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
|
||||
|
||||
/**
|
||||
* @notice return total supply of tokens
|
||||
*/
|
||||
function totalSupply() external view returns (uint256 supply);
|
||||
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
||||
}
|
128
contracts/token/StandardToken.sol
Normal file
128
contracts/token/StandardToken.sol
Normal file
@ -0,0 +1,128 @@
|
||||
pragma solidity ^0.5.3;
|
||||
|
||||
import "./ERC20Token.sol";
|
||||
|
||||
contract StandardToken is ERC20Token {
|
||||
|
||||
uint256 private supply;
|
||||
mapping (address => uint256) balances;
|
||||
mapping (address => mapping (address => uint256)) allowed;
|
||||
|
||||
constructor() internal { }
|
||||
|
||||
function transfer(
|
||||
address _to,
|
||||
uint256 _value
|
||||
)
|
||||
external
|
||||
returns (bool success)
|
||||
{
|
||||
return transfer(msg.sender, _to, _value);
|
||||
}
|
||||
|
||||
function approve(
|
||||
address _to,
|
||||
uint256 _value
|
||||
)
|
||||
external
|
||||
returns (bool success)
|
||||
{
|
||||
return approve(msg.sender, _to, _value);
|
||||
}
|
||||
|
||||
function transferFrom(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value
|
||||
)
|
||||
external
|
||||
returns (bool success)
|
||||
{
|
||||
if (balances[_from] >= _value &&
|
||||
allowed[_from][msg.sender] >= _value &&
|
||||
_value > 0) {
|
||||
allowed[_from][msg.sender] -= _value;
|
||||
return transfer(_from, _to, _value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function allowance(address _owner, address _spender)
|
||||
external
|
||||
view
|
||||
returns (uint256 remaining)
|
||||
{
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
|
||||
function balanceOf(address _owner)
|
||||
external
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
function totalSupply()
|
||||
external
|
||||
view
|
||||
returns(uint256 currentTotalSupply)
|
||||
{
|
||||
return supply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender.
|
||||
* @param _from The address that is approving the spend
|
||||
* @param _spender The address which will spend the funds.
|
||||
* @param _value The amount of tokens to be spent.
|
||||
*/
|
||||
function approve(address _from, address _spender, uint256 _value) internal returns (bool) {
|
||||
|
||||
// To change the approve amount you first have to reduce the addresses`
|
||||
// allowance to zero by calling `approve(_spender, 0)` if it is not
|
||||
// already 0 to mitigate the race condition described here:
|
||||
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
|
||||
require((_value == 0) || (allowed[_from][_spender] == 0), "Bad usage");
|
||||
|
||||
allowed[_from][_spender] = _value;
|
||||
emit Approval(_from, _spender, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function mint(
|
||||
address _to,
|
||||
uint256 _amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
balances[_to] += _amount;
|
||||
supply += _amount;
|
||||
emit Transfer(address(0x0), _to, _amount);
|
||||
}
|
||||
|
||||
function transfer(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value
|
||||
)
|
||||
internal
|
||||
returns (bool success)
|
||||
{
|
||||
if (balances[_from] >= _value && _value > 0) {
|
||||
balances[_from] -= _value;
|
||||
if(_to == address(0)) {
|
||||
supply -= _value;
|
||||
} else {
|
||||
balances[_to] += _value;
|
||||
}
|
||||
emit Transfer(_from, _to, _value);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
24
embark.json
Normal file
24
embark.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"contracts": ["contracts/**"],
|
||||
"app": {
|
||||
"js/dapp.js": ["app/dapp.js"],
|
||||
"index.html": "app/index.html",
|
||||
"images/": ["app/images/**"]
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/",
|
||||
"versions": {
|
||||
"web3": "1.0.0-beta",
|
||||
"solc": "0.5.3",
|
||||
"ipfs-api": "17.2.4"
|
||||
},
|
||||
"plugins": {
|
||||
"embarkjs-connector-web3": {}
|
||||
},
|
||||
"options": {
|
||||
"solc": {
|
||||
"optimize": true,
|
||||
"optimize-runs": 200
|
||||
}
|
||||
}
|
||||
}
|
4
embarkArtifacts/config/blockchain.json
Normal file
4
embarkArtifacts/config/blockchain.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"warnIfMetamask": true,
|
||||
"blockchainClient": "geth"
|
||||
}
|
686
embarkArtifacts/embarkjs.js
Normal file
686
embarkArtifacts/embarkjs.js
Normal file
File diff suppressed because one or more lines are too long
1
embarkArtifacts/modules/embarkjs
Symbolic link
1
embarkArtifacts/modules/embarkjs
Symbolic link
@ -0,0 +1 @@
|
||||
/Users/Barry/.nvm/versions/node/v10.12.0/lib/node_modules/embark/node_modules/embarkjs/dist/node
|
1
embarkArtifacts/modules/eth-ens-namehash
Symbolic link
1
embarkArtifacts/modules/eth-ens-namehash
Symbolic link
@ -0,0 +1 @@
|
||||
/Users/Barry/.nvm/versions/node/v10.12.0/lib/node_modules/embark/node_modules/eth-ens-namehash
|
1
embarkArtifacts/modules/ipfs-api
Symbolic link
1
embarkArtifacts/modules/ipfs-api
Symbolic link
@ -0,0 +1 @@
|
||||
/Users/Barry/.nvm/versions/node/v10.12.0/lib/node_modules/embark/node_modules/ipfs-api/src
|
1
embarkArtifacts/modules/web3
Symbolic link
1
embarkArtifacts/modules/web3
Symbolic link
@ -0,0 +1 @@
|
||||
/Users/Barry/.nvm/versions/node/v10.12.0/lib/node_modules/embark/node_modules/web3/src
|
212
package-lock.json
generated
Normal file
212
package-lock.json
generated
Normal file
@ -0,0 +1,212 @@
|
||||
{
|
||||
"name": "app_name",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz",
|
||||
"integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.12.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"regenerator-runtime": {
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz",
|
||||
"integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-runtime": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
|
||||
"requires": {
|
||||
"core-js": "^2.4.0",
|
||||
"regenerator-runtime": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
|
||||
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
|
||||
},
|
||||
"core-js": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.4.tgz",
|
||||
"integrity": "sha512-05qQ5hXShcqGkPZpXEFLIpxayZscVD2kuMBZewxiIPPEagukO4mqgPA9CWhUvFBJfy3ODdK2p9xyHh7FTU9/7A=="
|
||||
},
|
||||
"dom-helpers": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2"
|
||||
}
|
||||
},
|
||||
"invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"keycode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
|
||||
"integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ="
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.6.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
|
||||
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"prop-types-extra": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.0.tgz",
|
||||
"integrity": "sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg==",
|
||||
"requires": {
|
||||
"react-is": "^16.3.2",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "16.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.8.1.tgz",
|
||||
"integrity": "sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.13.1"
|
||||
}
|
||||
},
|
||||
"react-bootstrap": {
|
||||
"version": "0.32.1",
|
||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.32.1.tgz",
|
||||
"integrity": "sha512-RbfzKUbsukWsToWqGHfCCyMFq9QQI0TznutdyxyJw6dih2NvIne25Mrssg8LZsprqtPpyQi8bN0L0Fx3fUsL8Q==",
|
||||
"requires": {
|
||||
"babel-runtime": "^6.11.6",
|
||||
"classnames": "^2.2.5",
|
||||
"dom-helpers": "^3.2.0",
|
||||
"invariant": "^2.2.1",
|
||||
"keycode": "^2.1.2",
|
||||
"prop-types": "^15.5.10",
|
||||
"prop-types-extra": "^1.0.1",
|
||||
"react-overlays": "^0.8.0",
|
||||
"react-prop-types": "^0.4.0",
|
||||
"react-transition-group": "^2.0.0",
|
||||
"uncontrollable": "^4.1.0",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.1.tgz",
|
||||
"integrity": "sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.13.1"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.1.tgz",
|
||||
"integrity": "sha512-ioMCzVDWvCvKD8eeT+iukyWrBGrA3DiFYkXfBsVYIRdaREZuBjENG+KjrikavCLasozqRWTwFUagU/O4vPpRMA=="
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"react-overlays": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-0.8.3.tgz",
|
||||
"integrity": "sha512-h6GT3jgy90PgctleP39Yu3eK1v9vaJAW73GOA/UbN9dJ7aAN4BTZD6793eI1D5U+ukMk17qiqN/wl3diK1Z5LA==",
|
||||
"requires": {
|
||||
"classnames": "^2.2.5",
|
||||
"dom-helpers": "^3.2.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"prop-types-extra": "^1.0.1",
|
||||
"react-transition-group": "^2.2.0",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-prop-types": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz",
|
||||
"integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=",
|
||||
"requires": {
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "2.5.3",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz",
|
||||
"integrity": "sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==",
|
||||
"requires": {
|
||||
"dom-helpers": "^3.3.1",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.1.tgz",
|
||||
"integrity": "sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"uncontrollable": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-4.1.0.tgz",
|
||||
"integrity": "sha1-4DWCkSUuGGUiLZCTmxny9J+Bwak=",
|
||||
"requires": {
|
||||
"invariant": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
|
||||
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
package.json
Normal file
18
package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "app_name",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "Gruntfile.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"homepage": "",
|
||||
"dependencies": {
|
||||
"embarkjs-connector-web3": "^4.0.0",
|
||||
"react": "^16.3.2",
|
||||
"react-bootstrap": "0.32.1",
|
||||
"react-dom": "^16.3.2"
|
||||
}
|
||||
}
|
41
test/simple_storage_spec.js
Normal file
41
test/simple_storage_spec.js
Normal file
@ -0,0 +1,41 @@
|
||||
/*global contract, config, it, assert*/
|
||||
const SimpleStorage = require('Embark/contracts/SimpleStorage');
|
||||
|
||||
let accounts;
|
||||
|
||||
// For documentation please see https://embark.status.im/docs/contracts_testing.html
|
||||
config({
|
||||
//deployment: {
|
||||
// accounts: [
|
||||
// // you can configure custom accounts with a custom balance
|
||||
// // see https://embark.status.im/docs/contracts_testing.html#Configuring-accounts
|
||||
// ]
|
||||
//},
|
||||
contracts: {
|
||||
"SimpleStorage": {
|
||||
args: [100]
|
||||
}
|
||||
}
|
||||
}, (_err, web3_accounts) => {
|
||||
accounts = web3_accounts
|
||||
});
|
||||
|
||||
contract("SimpleStorage", function () {
|
||||
this.timeout(0);
|
||||
|
||||
it("should set constructor value", async function () {
|
||||
let result = await SimpleStorage.methods.storedData().call();
|
||||
assert.strictEqual(parseInt(result, 10), 100);
|
||||
});
|
||||
|
||||
it("set storage value", async function () {
|
||||
await SimpleStorage.methods.set(150).send();
|
||||
let result = await SimpleStorage.methods.get().call();
|
||||
assert.strictEqual(parseInt(result, 10), 150);
|
||||
});
|
||||
|
||||
it("should have account with balance", async function() {
|
||||
let balance = await web3.eth.getBalance(accounts[0]);
|
||||
assert.ok(parseInt(balance, 10) > 0);
|
||||
});
|
||||
});
|
59
test/subscription_spec.js
Normal file
59
test/subscription_spec.js
Normal file
@ -0,0 +1,59 @@
|
||||
/*global contract, config, it, assert*/
|
||||
const Subscription = require('Embark/contracts/Subscription');
|
||||
const StandardToken = require('Embark/contracts/StandardToken');
|
||||
|
||||
let accounts;
|
||||
let payor;
|
||||
let receiver;
|
||||
const USD_DECIMALS= 18
|
||||
const USD_PRECISION = 10**USD_DECIMALS
|
||||
const SECONDS_IN_A_YEAR = 31557600 // 365.25 days
|
||||
const ONE = 1e18
|
||||
const ETH = '0x0'
|
||||
const rateExpiryTime = 1000
|
||||
|
||||
function getSalary(salary) {
|
||||
const amount = BigInt(salary);
|
||||
return (amount * BigInt(USD_PRECISION)) / BigInt(SECONDS_IN_A_YEAR)
|
||||
}
|
||||
|
||||
// For documentation please see https://embark.status.im/docs/contracts_testing.html
|
||||
config({
|
||||
//deployment: {
|
||||
// accounts: [
|
||||
// // you can configure custom accounts with a custom balance
|
||||
// // see https://embark.status.im/docs/contracts_testing.html#Configuring-accounts
|
||||
// ]
|
||||
//},
|
||||
contracts: {
|
||||
"Subscription": {
|
||||
args: []
|
||||
},
|
||||
"StandardToken": {
|
||||
args: []
|
||||
}
|
||||
}
|
||||
}, (_err, web3_accounts) => {
|
||||
accounts = web3_accounts
|
||||
payor = web3_accounts[0]
|
||||
receiver = web3_accounts[1]
|
||||
});
|
||||
|
||||
|
||||
contract("subscription", function () {
|
||||
this.timeout(0);
|
||||
|
||||
it("should create an agreement", async function () {
|
||||
//const salary1 = (new web3.BigNumber(100000)).times(USD_PRECISION).dividedToIntegerBy(SECONDS_IN_A_YEAR)
|
||||
|
||||
let balance = await web3.eth.getBalance(accounts[8])
|
||||
console.log({accounts, balance}, StandardToken.options.address)
|
||||
// Subscription.methods.createAgreement(
|
||||
// receiver,
|
||||
// payor,
|
||||
// StandardToken.address
|
||||
|
||||
// )
|
||||
});
|
||||
|
||||
});
|
195
yarn.lock
Normal file
195
yarn.lock
Normal file
@ -0,0 +1,195 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/runtime@^7.1.2":
|
||||
version "7.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.3.tgz#79888e452034223ad9609187a0ad1fe0d2ad4bdc"
|
||||
integrity sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
babel-runtime@^6.11.6:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
|
||||
dependencies:
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.11.0"
|
||||
|
||||
classnames@^2.2.5:
|
||||
version "2.2.6"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
|
||||
|
||||
core-js@^2.4.0:
|
||||
version "2.6.5"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895"
|
||||
integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==
|
||||
|
||||
dom-helpers@^3.2.0, dom-helpers@^3.2.1, dom-helpers@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
|
||||
integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.2"
|
||||
|
||||
embarkjs-connector-web3@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/embarkjs-connector-web3/-/embarkjs-connector-web3-4.0.0.tgz#d474b23649668730082c7f6fa74b6a8c2cd0a447"
|
||||
integrity sha512-mqLDRGawEfyqXgoSb2NgTwhlbAHwDrk7eyHrtEvywWgKfEPer+S+5IN+KGXi85d7QxcNKJSZ+BHve8wvWX0FfQ==
|
||||
|
||||
invariant@^2.1.0, invariant@^2.2.1:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
|
||||
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
|
||||
keycode@^2.1.2:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04"
|
||||
integrity sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=
|
||||
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
prop-types-extra@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/prop-types-extra/-/prop-types-extra-1.1.0.tgz#32609910ea2dcf190366bacd3490d5a6412a605f"
|
||||
integrity sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg==
|
||||
dependencies:
|
||||
react-is "^16.3.2"
|
||||
warning "^3.0.0"
|
||||
|
||||
prop-types@^15.5.10, prop-types@^15.6.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
dependencies:
|
||||
loose-envify "^1.4.0"
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.8.1"
|
||||
|
||||
react-bootstrap@0.32.1:
|
||||
version "0.32.1"
|
||||
resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-0.32.1.tgz#60624c1b48a39d773ef6cce6421a4f33ecc166bb"
|
||||
integrity sha512-RbfzKUbsukWsToWqGHfCCyMFq9QQI0TznutdyxyJw6dih2NvIne25Mrssg8LZsprqtPpyQi8bN0L0Fx3fUsL8Q==
|
||||
dependencies:
|
||||
babel-runtime "^6.11.6"
|
||||
classnames "^2.2.5"
|
||||
dom-helpers "^3.2.0"
|
||||
invariant "^2.2.1"
|
||||
keycode "^2.1.2"
|
||||
prop-types "^15.5.10"
|
||||
prop-types-extra "^1.0.1"
|
||||
react-overlays "^0.8.0"
|
||||
react-prop-types "^0.4.0"
|
||||
react-transition-group "^2.0.0"
|
||||
uncontrollable "^4.1.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
react-dom@^16.3.2:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
|
||||
integrity sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
scheduler "^0.13.6"
|
||||
|
||||
react-is@^16.3.2, react-is@^16.8.1:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
|
||||
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
|
||||
|
||||
react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-overlays@^0.8.0:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.8.3.tgz#fad65eea5b24301cca192a169f5dddb0b20d3ac5"
|
||||
integrity sha512-h6GT3jgy90PgctleP39Yu3eK1v9vaJAW73GOA/UbN9dJ7aAN4BTZD6793eI1D5U+ukMk17qiqN/wl3diK1Z5LA==
|
||||
dependencies:
|
||||
classnames "^2.2.5"
|
||||
dom-helpers "^3.2.1"
|
||||
prop-types "^15.5.10"
|
||||
prop-types-extra "^1.0.1"
|
||||
react-transition-group "^2.2.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
react-prop-types@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.4.0.tgz#f99b0bfb4006929c9af2051e7c1414a5c75b93d0"
|
||||
integrity sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
react-transition-group@^2.0.0, react-transition-group@^2.2.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
|
||||
dependencies:
|
||||
dom-helpers "^3.4.0"
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react@^16.3.2:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
|
||||
integrity sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
scheduler "^0.13.6"
|
||||
|
||||
regenerator-runtime@^0.11.0:
|
||||
version "0.11.1"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
||||
|
||||
regenerator-runtime@^0.13.2:
|
||||
version "0.13.2"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
|
||||
integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
|
||||
|
||||
scheduler@^0.13.6:
|
||||
version "0.13.6"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889"
|
||||
integrity sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
uncontrollable@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-4.1.0.tgz#e0358291252e1865222d90939b19f2f49f81c1a9"
|
||||
integrity sha1-4DWCkSUuGGUiLZCTmxny9J+Bwak=
|
||||
dependencies:
|
||||
invariant "^2.1.0"
|
||||
|
||||
warning@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
|
||||
integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
Loading…
x
Reference in New Issue
Block a user