Commit 1d32190d authored by therealwolf's avatar therealwolf 💯
Browse files

init

parent 4659b1ce
app
# Logs
logs
*.log
......
......@@ -16,6 +16,11 @@ IN THE SOFTWARE.
## Updates
### 1.0.1 Release
- Added Conversion (HBD => HIVE) and Collateralized Conversion (HIVE => HBD)
- Improved `Send` page to make it easier to deposit to/withdraw from savings
### 1.0.0 Release
- Converted to community owned project
......
......@@ -94,6 +94,15 @@ export const ACCOUNT_TRANSFER_TO_SAVINGS_COMPLETED =
export const ACCOUNT_CONTACTS_ADD = "ACCOUNT_CONTACTS_ADD";
export const ACCOUNT_CONTACTS_REMOVE = "ACCOUNT_CONTACTS_REMOVE";
export const ACCOUNT_CONVERT_COMPLETED = "ACCOUNT_CONVERT_COMPLETED";
export const ACCOUNT_CONVERT_STARTED = "ACCOUNT_CONVERT_STARTED";
export const ACCOUNT_CONVERT_FAILED = "ACCOUNT_CONVERT_FAILED";
export const ACCOUNT_CONVERT_RESOLVED = "ACCOUNT_CONVERT_RESOLVED";
export const ACCOUNT_COLLATERALIZED_CONVERT_COMPLETED = "ACCOUNT_COLLATERALIZED_CONVERT_COMPLETED";
export const ACCOUNT_COLLATERALIZED_CONVERT_STARTED = "ACCOUNT_COLLATERALIZED_CONVERT_STARTED";
export const ACCOUNT_COLLATERALIZED_CONVERT_FAILED = "ACCOUNT_COLLATERALIZED_CONVERT_FAILED";
export const ACCOUNT_COLLATERALIZED_CONVERT_RESOLVED = "ACCOUNT_COLLATERALIZED_CONVERT_RESOLVED";
export function claimRewardBalance(wif: string, params: object) {
return (dispatch: () => void) => {
let { account, reward_hive, reward_hbd, reward_vests } = params;
......@@ -342,6 +351,77 @@ export function transferCompleted() {
};
}
export function convert(wif, params) {
return (dispatch: () => void) => {
var { owner, requestid, amount } = params;
dispatch({
type: ACCOUNT_CONVERT_STARTED
});
if (hive.config.get('address_prefix') === 'TST') {
//if testnet
amount = amount.replace("HIVE", "TESTS");
amount = amount.replace("HBD", "TBD");
}
if (!requestid) requestid = Math.floor(Date.now() / 1000)
hive.broadcast.convert(wif, owner, requestid, amount, (err, result) => {
if (err) {
dispatch({
type: ACCOUNT_CONVERT_FAILED,
payload: err
});
} else {
refreshAccountData([owner]);
dispatch({
type: ACCOUNT_CONVERT_RESOLVED
});
}
});
};
}
export function convertCompleted() {
return {
type: ACCOUNT_CONVERT_COMPLETED
};
}
export function collateralizedConvert(wif, params) {
return (dispatch: () => void) => {
var { owner, requestid, amount } = params;
dispatch({
type: ACCOUNT_COLLATERALIZED_CONVERT_STARTED
});
if (hive.config.get('address_prefix') === 'TST') {
//if testnet
amount = amount.replace("HIVE", "TESTS");
amount = amount.replace("HBD", "TBD");
}
if (!requestid) requestid = Math.floor(Date.now() / 1000)
console.log('hive', hive)
hive.broadcast.collateralizedConvert(wif, owner, requestid, amount, (err, result) => {
if (err) {
dispatch({
type: ACCOUNT_COLLATERALIZED_CONVERT_FAILED,
payload: err
});
} else {
refreshAccountData([owner]);
dispatch({
type: ACCOUNT_COLLATERALIZED_CONVERT_RESOLVED
});
}
});
};
}
export function collateralizedConvertCompleted() {
return {
type: ACCOUNT_COLLATERALIZED_CONVERT_COMPLETED
};
}
export function transferFromSavings(wif, params) {
return (dispatch: () => void) => {
var { from, requestId, to, amount, memo } = params;
......@@ -666,7 +746,7 @@ export function customJson(wif, params) {
dispatch({
type: ACCOUNT_CUSTOM_JSON_STARTED
});
hive.broadcast.customJson(wif, auths, postingAuths, id, json, function(
hive.broadcast.customJson(wif, auths, postingAuths, id, json, function (
err,
result
) {
......@@ -698,7 +778,7 @@ export function send(wif, params) {
dispatch({
type: ACCOUNT_CUSTOM_OPS_STARTED
});
hive.broadcast.send({ operations, extensions }, { posting: wif }, function(
hive.broadcast.send({ operations, extensions }, { posting: wif }, function (
err,
result
) {
......
......@@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>Vessel - 1.0.0</title>
<title>Vessel - 1.0.1</title>
<script>
(function() {
if (!process.env.HOT) {
......
......@@ -75,7 +75,7 @@ export default class AccountsProxy extends Component {
let { delegator, delegatee, id } = props.value.delegatee;
delegatee = delegatee.toLowerCase().replace('@', '');
const permissions = this.props.keys.permissions;
this.setState({undelegateError: false})
this.setState({ undelegateError: false })
this.props.actions.useKey('setDelegateVestingShares', { delegator, delegatee, vestingShares: 0.000000 }, permissions[delegator])
}
handleVestingSharesEdit = (e, props) => {
......@@ -299,7 +299,9 @@ export default class AccountsProxy extends Component {
<Header.Subheader>
<strong>
<NumericLabel params={numberFormat}>{vests}</NumericLabel>
</strong> VESTS
</strong>
{' '}
VESTS
</Header.Subheader>
</Header>
</Table.Cell>
......@@ -318,8 +320,7 @@ export default class AccountsProxy extends Component {
<NumericLabel params={numberFormat}>{delegatedAmount}</NumericLabel>
) : (
0
)
}
)}
<Header.Subheader>
VESTS
</Header.Subheader>
......@@ -343,42 +344,41 @@ export default class AccountsProxy extends Component {
</Table.Row>
</Table.Header>
<Table.Body>
{delegatees.map((delegatee) => {
const vests = parseFloat(delegatee.vesting_shares.split(" ")[0])
return (
<Table.Row key={delegatee.id}>
<Table.Cell>
<AccountName name={delegatee.delegatee} />
</Table.Cell>
<Table.Cell>
<NumericLabel params={numberFormat}>{vests}</NumericLabel>
</Table.Cell>
<Table.Cell>
<Button.Group>
<Button
color="black"
size="small"
icon="pencil"
value={{ delegatee }}
onClick={this.handleVestingSharesEdit}
/>
<Button
color="orange"
size="small"
icon="trash"
value={{ delegatee }}
onClick={this.handleVestingSharesRemove}
/>
</Button.Group>
</Table.Cell>
</Table.Row>
)
})}
{delegatees.map((delegatee) => {
const vests = parseFloat(delegatee.vesting_shares.split(" ")[0])
return (
<Table.Row key={delegatee.id}>
<Table.Cell>
<AccountName name={delegatee.delegatee} />
</Table.Cell>
<Table.Cell>
<NumericLabel params={numberFormat}>{vests}</NumericLabel>
</Table.Cell>
<Table.Cell>
<Button.Group>
<Button
color="black"
size="small"
icon="pencil"
value={{ delegatee }}
onClick={this.handleVestingSharesEdit}
/>
<Button
color="orange"
size="small"
icon="trash"
value={{ delegatee }}
onClick={this.handleVestingSharesRemove}
/>
</Button.Group>
</Table.Cell>
</Table.Row>
)
})}
</Table.Body>
</Table>
)
: 'No active delegations'
}
: 'No active delegations'}
</Table.Cell>
<Table.Cell>
<Button
......
......@@ -73,6 +73,7 @@ const exchangeSupportingEncryption = ["bittrex"];
const defaultState = {
sourceType: "liquid",
destinationType: "liquid",
from: "",
to: "",
amount: "",
......@@ -123,18 +124,38 @@ export default class Send extends Component {
});
}
handleSourceTypeChange = (e: SyntheticEvent, { value }: { value: any }) => {
this.setState({
const obj = {
sourceType: value
}
if (this.state.destinationType === 'same_account') {
obj.destinationType = value === 'liquid' ? 'savings' : 'liquid'
} else {
obj.destinationType = value === 'liquid' ? 'liquid' : 'savings'
}
this.setState(obj);
};
handleDestinationTypeChange = (e: SyntheticEvent, { value }: { value: any }) => {
this.setState({
destinationType: value
});
};
handleDestinationChange = (e: SyntheticEvent, { value }: { value: any }) => {
this.setState({
const obj = {
to: "",
memo: "",
destination: value,
encryptMemo: false,
memoEncrypted: false
});
}
if (value === 'exchange') {
obj.destinationType = 'liquid'
} else if (value === 'same_account') {
obj.destinationType = this.state.sourceType === 'liquid' ? 'savings' : 'liquid'
obj.to = this.state.from
} else if (this.state.destinationType === 'same_account') {
obj.destinationType = this.state.sourceType === 'liquid' ? 'liquid' : 'savings'
}
this.setState(obj);
};
handleSymbolChange = (e: SyntheticEvent, { value }: { value: any }) => {
const detectMemo = this.detectMemo(this.state.to, value);
......@@ -315,7 +336,7 @@ export default class Send extends Component {
const amountFormat = [amount, symbol].join(" ");
if (this.state.sourceType === "liquid") {
this.props.actions.useKey(
this.state.destination.search("savings") === -1
this.state.destinationType !== "savings" || this.state.destination === 'exchange'
? "transfer"
: "transferToSavings",
{ from, to, amount: amountFormat, memo: usedMemo },
......@@ -423,20 +444,55 @@ export default class Send extends Component {
const availableAmount = accounts[this.state.from][field];
const errorLabel = <Label color="red" pointing />;
let modal = false;
const getDestinationTypeField = () => {
if (this.state.destination === 'exchange') return null
return <Grid.Column width={4} style={{ marginTop: '25px' }}>
<div className="field" style={{ marginBottom: '5px' }}>
<label htmlFor="from">Select the specific destination</label>
</div>
<Grid.Row style={{ display: 'flex' }}>
<Form.Field
control={Radio}
name="destinationType"
label="liquid"
value="liquid"
checked={this.state.destinationType === "liquid"}
onChange={this.handleDestinationTypeChange}
style={{ marginRight: '10px' }}
/>
<Form.Field
control={Radio}
name="destinationType"
label="savings"
value="savings"
checked={this.state.destinationType === "savings"}
onChange={this.handleDestinationTypeChange}
/>
</Grid.Row>
</Grid.Column>
}
let toField = (
<Form.Field
control={Input}
name="to"
label="Enter the account name"
placeholder="Enter the account name to send to..."
value={this.state.to}
onChange={this.handleToChange}
// validationErrors={{
// accountName: 'Invalid account name'
// }}
errorLabel={errorLabel}
/>
<Grid.Row>
<Form.Field
control={Input}
name="to"
label="Enter the account name"
placeholder={'Enter the account name to send to...'}
value={this.state.to}
onChange={this.handleToChange}
// validationErrors={{
// accountName: 'Invalid account name'
// }}
errorLabel={errorLabel}
/>
</Grid.Row>
);
let destinationTypeField = getDestinationTypeField()
let encryptedField = false;
if (this.state.destination === "exchange") {
let externalLink = false;
......@@ -551,6 +607,12 @@ export default class Send extends Component {
{this.state.destination.replace("account_", "")}
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell textAlign="right">Destination Type:</Table.Cell>
<Table.Cell>
{this.state.destinationType}
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell textAlign="right">From:</Table.Cell>
<Table.Cell>{this.state.from}</Table.Cell>
......@@ -697,10 +759,11 @@ export default class Send extends Component {
<div className="field">
<label htmlFor="destination">Send to a...</label>
</div>
<Form.Field
control={Radio}
name="destination"
label="another user (liquid)"
label="another user"
value="account_liquid"
checked={this.state.destination === "account_liquid"}
onChange={this.handleDestinationChange}
......@@ -716,21 +779,24 @@ export default class Send extends Component {
<Form.Field
control={Radio}
name="destination"
label="saved contact"
value="contact"
checked={this.state.destination === "contact"}
label="same account"
value="same_account"
checked={this.state.destination === "same_account"}
onChange={this.handleDestinationChange}
/>
<Form.Field
control={Radio}
name="destination"
label="another user (savings)"
value="account_savings"
checked={this.state.destination === "account_savings"}
label="saved contact"
value="contact"
checked={this.state.destination === "contact"}
onChange={this.handleDestinationChange}
/>
</Grid.Column>
<Grid.Column width={12}>{toField}</Grid.Column>
<Grid.Column width={12}>
<Grid.Column width={12}>{toField}</Grid.Column>
<Grid.Column width={12}>{destinationTypeField}</Grid.Column>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column width={4}>
......
......@@ -54,7 +54,11 @@ const opTemplates = {
},
convert: {
color: 'orange',
message: (op) => `Convert ${op.amount} to equiv HIVE (5 day wait).`
message: (op) => `Convert ${op.amount} to equiv HIVE in 3.5 days.`
},
collateralizedConvert: {
color: 'orange',
message: (op) => `Collateralized Convert ${op.amount} to equiv HBD and HIVE coll. return in 3.5 days.`
},
delegate_vesting_shares: {
color: 'orange',
......@@ -115,8 +119,8 @@ export default class OperationsPrompt extends Component {
getPromptsFromMeta = (props) => {
return Object.keys(props.meta).map((field) => {
const meta = props.meta[field]
if(meta.prompt) {
switch(meta.type) {
if (meta.prompt) {
switch (meta.type) {
case "asset":
case "hbd":
case "hive":
......@@ -170,7 +174,7 @@ export default class OperationsPrompt extends Component {
}
setAccount = (e, { value }) => {
this.setState({account: value})
this.setState({ account: value })
this.props.accountChange(value)
}
......@@ -178,27 +182,27 @@ export default class OperationsPrompt extends Component {
const opType = op[0]
const opData = op[1]
const opTemplate = opTemplates[opType]
if(!opTemplate) {
if (!opTemplate) {
return (
<Segment key={idx} attached>
<Label color='red' style={{marginRight: '1em'}}>{op[0]}</Label>
<Label color='red' style={{ marginRight: '1em' }}>{op[0]}</Label>
Review this operation via the JSON.
</Segment>
)
}
return (
<Segment key={idx} attached>
<Label color={opTemplate['color']} style={{marginRight: '1em'}}>{op[0]}</Label>
<Label color={opTemplate['color']} style={{ marginRight: '1em' }}>{op[0]}</Label>
{opTemplate.message(opData)}
</Segment>
)
}
listOps = (ops) => {
if(ops.length === 1) {
if (ops.length === 1) {
const op = this.props.ops[0]
const opData = op[1]
switch(ops[0][0]) {
switch (ops[0][0]) {
case 'delegate_vesting_shares':
return [
<Header attached='top' key='op-header'><Icon name='power' />Delegate Hive Power</Header>,
......@@ -281,15 +285,15 @@ export default class OperationsPrompt extends Component {
<Segment attached='bottom'>
<Accordion>
<Accordion.Title active={this.state.displayRawJSON === true} index={0} onClick={this.handleClick}>
<Header style={{margin: 0}}>
<Header.Content style={{padding: 0}}>
<Header style={{ margin: 0 }}>
<Header.Content style={{ padding: 0 }}>
<Icon name='dropdown' />
Transaction JSON
</Header.Content>
</Header>
</Accordion.Title>
<Accordion.Content active={this.state.displayRawJSON === true}>
<Segment padded secondary><pre>{JSON.stringify(ops, null, 2) }</pre></Segment>
<Segment padded secondary><pre>{JSON.stringify(ops, null, 2)}</pre></Segment>
</Accordion.Content>
</Accordion>
</Segment>
......
// @flow
import hive from "@hiveio/hive-js";
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { Redirect } from 'react-router';
import { connect } from 'react-redux';
import MenuBar from './MenuBar';
import ContentBar from '../components/ContentBar';
import {
Header,
Divider,
Icon,
Button,
Checkbox,
Grid,
Label,
Message,
Modal,
Radio,
Segment,
Select,
Table
} from 'semantic-ui-react';
import * as AccountActions from '../actions/account';
import * as KeysActions from '../actions/keys';
import { Form, Input } from "formsy-semantic-ui-react";
const defaultState = {
account: "",
id: "",
symbol: "HIVE",
conversionType: 'HIVEtoHBD',
requestid: null,
generatedRequestId: null,
amount: 0,
modalPreview: false,
};
class ConvertPage extends Component {
constructor(props) {
super(props);
this.state = Object.assign({}, defaultState, {
account: props.keys.names[0],
network: props.hive.props.network || "Hive"
})
if (props.keys.names[0]) this.handleAccountChange({ e: null }, { value: props.keys.names[0] })
}
render() {
const accounts = this.props.account.accounts;
const keys = this.props.keys;
const availableFrom = keys.names.map(name => {
const hasPermission =
keys.permissions[name].type === "active" ||
keys.permissions[name].type === "owner";
return hasPermission
? {
key: name,
text: name,
value: name
}
: {
key: name,
disabled: true,
text: name + " (unavailable - active/owner key not loaded)"
};
});
const getConversionExplanationField = () => {
return this.state.conversionType === 'HIVEtoHBD' ? (
<Grid.Column>
<Header.Subheader>HIVE can be converted to HBD by using 2x the amount of HIVE as collateral + 5% fee. You'll receive the HBD instantly. After 3.5 days, you'll receive some of your HIVE collateral back. If the HIVE price remained stable or increased, you'll get back your collateral in full or even more. If the HIVE price decreased, you'll get back less collateral, since the HBD you received can now buy more HIVE.</Header.Subheader>
<br />
<Header.Subheader>When to use: If HBD can be sold for more than $1.05 on exchanges and the HIVE price over the next 3.5 days remains stable or increases in price.</Header.Subheader>
<br />
<Header.Subheader>NOTE: This conversion is risky. Please make sure you know what you're doing!</Header.Subheader>
</Grid.Column>) : (<Grid.Column><Header.Subheader>HBD can be converted into $1 USD worth of HIVE determined by the 3.5 days median price. You'll receive your HIVE after 3.5 days.</Header.Subheader>
<br />
<Header.Subheader>When to use: If HBD can be bought for less than $1 on exchanges and the HIVE price over the next 3.5 days remains stable or falls in price.</Header.Subheader></Grid.Column>)
}
const conversionExplanationField = getConversionExplanationField()