Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/components/BalanceInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { observer, inject } from 'mobx-react';
import SyndicateStore from '../stores/Syndicate';
import { BlockContainer, BlockElement, BlockFooter, BlockHeader } from './Shared';
import WeiDisplay from './WeiDisplay';
import EthereumStore from '../stores/Ethereum';

@inject('syndicateStore', 'ethereumStore')
@observer
export default class BalanceInfo extends React.Component<{
syndicateStore?: SyndicateStore,
ethereumStore?: EthereumStore
}> {
componentDidMount() {
this.props.syndicateStore.loadBalance(this.props.ethereumStore.activeAddress);
}

render() {
console.log(this.props.syndicateStore.balances['0xddeC6C333538fCD3de7cfB56D6beed7Fd8dEE604']);
return (
<BlockContainer>
<BlockHeader>
Your Balance
</BlockHeader>
<BlockElement>
Available: <WeiDisplay wei={this.props.syndicateStore.balances[this.props.ethereumStore.activeAddress]} />
<br />
<button onClick={() => {
this.props.syndicateStore.withdraw(this.props.ethereumStore.activeAddress);
}}>withdraw</button>
<br />
</BlockElement>
<BlockFooter />
</BlockContainer>
);
}
}
12 changes: 0 additions & 12 deletions src/components/ContractInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { observer, inject } from 'mobx-react';
import EthereumStore from '../stores/Ethereum';
import SyndicateStore from '../stores/Syndicate';
import Colors from './Colors';
import WeiDisplay from './WeiDisplay';

@inject('ethereumStore', 'syndicateStore')
@observer
Expand Down Expand Up @@ -51,17 +50,6 @@ export default class ContractInfo extends React.Component <{
{contractAddress}
</a>
</div>
<div>
{
// Available Balance: <WeiDisplay wei={this.props.syndicateStore.balances[this.props.ethereumStore.activeAddress]} />
// <br />
}
<button type="button" onClick={() => {
this.props.syndicateStore.withdraw(
this.props.ethereumStore.activeAddress
);
}}>Withdraw</button>
</div>
</div>
</BlockElement>
<BlockFooter />
Expand Down
2 changes: 2 additions & 0 deletions src/components/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ContractInfo from './ContractInfo';
import CreatePayment from './CreatePayment';
import PaymentCell from './PaymentCell';
import SyndicateStore from '../stores/Syndicate';
import BalanceInfo from './BalanceInfo';

const HeaderText = styled.div`
font-family: Helvetica;
Expand Down Expand Up @@ -39,6 +40,7 @@ export default class Home extends React.Component <{
<Header />
<Container>
<ContractInfo />
<BalanceInfo />
<CreatePayment />
<HeaderText>
Payments
Expand Down
6 changes: 6 additions & 0 deletions src/components/PaymentCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import EthereumStore from '../stores/Ethereum';
import TimerDisplay from './TimerDisplay';
import ForkControls from './ForkControls';
import PaymentInfo from './PaymentInfo';
import PaymentGraph from './PaymentGraph';

const TextSpan = styled.span`
margin-left: 4px;
Expand Down Expand Up @@ -41,6 +42,11 @@ export default class PaymentCell extends React.Component <{
<BlockElement>
<PaymentInfo payment={this.props.payment} />
<ForkControls payment={this.props.payment} />
{
this.props.payment.isForked && !this.props.payment.isFork ? (
<PaymentGraph payment={this.props.payment} />
) : null
}
</BlockElement>
<BlockFooter>
</BlockFooter>
Expand Down
61 changes: 61 additions & 0 deletions src/components/PaymentGraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import { Payment } from '../stores/Syndicate';
import SyndicateStore from '../stores/Syndicate';
import { inject, observer } from 'mobx-react';

@inject('syndicateStore')
@observer
export default class PaymentGraph extends React.Component<{
payment: Payment,
syndicateStore?: SyndicateStore
}> {
state: {
paymentChain: Payment[]
} = {
paymentChain: []
};

canvasRef: React.RefObject<HTMLCanvasElement>;

constructor(props: any) {
super(props);
this.canvasRef = React.createRef();
}

componentDidMount() {
this.draw();
}

componentDidUpdate() {
this.draw();
}

draw = () => {
const canvas = this.canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');

const start = +this.props.payment.timestamp;
const now = +new Date() / 1000;
const end = +this.props.payment.timestamp + +this.props.payment.time;

ctx.fillStyle = '#000000';
ctx.strokeStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
const drawNode = (x: number, y: number, radius: number = 10) => {
ctx.arc(x, y, radius, 0, 2 * Math.PI);
ctx.lineWidth = 1;
ctx.stroke();
};
let currentHeight = canvas.height / 2;
drawNode(15, currentHeight);
}

render() {
return (
<canvas
ref={this.canvasRef}
/>
);
}
}
13 changes: 12 additions & 1 deletion src/components/PaymentInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default class PaymentInfo extends React.Component<{
shouldComponentUpdate() {
return true;
}

render() {
return (
<>
Expand All @@ -33,6 +33,16 @@ export default class PaymentInfo extends React.Component<{
Total Paid: <WeiDisplay wei={this.props.payment.weiPaid} />
<br />
Total Available: <WeiDisplay wei={this.props.payment.weiOwed} />
<br />
Is Fork: {this.props.payment.isFork ? 'YES' : 'NO'}
{
this.props.payment.isFork ? (
<>
<br />
Parent Payment Index: {this.props.payment.parentIndex}
</>
) : null
}
{
this.props.payment.settled ? null : (
<>
Expand All @@ -47,6 +57,7 @@ export default class PaymentInfo extends React.Component<{
</>
)
}
<br />
</>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/WeiDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class WeiDisplay extends React.Component <{
gdaxStore?: any
}> {
render() {
const etherValue = +web3.utils.fromWei(this.props.wei.toString());
const etherValue = +web3.utils.fromWei((this.props.wei || 0).toString());
const roundedEtherValue = Math.round(etherValue * 1e5) / 1e5;
const usdValue = Math.round(1e2 * roundedEtherValue * this.props.gdaxStore.ethPrice) / 1e2;
return (
Expand Down
74 changes: 64 additions & 10 deletions src/stores/Syndicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,26 @@ export class Payment {
time: string|number|BN;
weiValue: string|number|BN;
weiPaid: string|number|BN;

constructor(obj: any) {
this.index = obj.index;
isFork: boolean;
parentIndex: number;
isForked: boolean;
fork1Index: number;
fork2Index: number;

constructor(obj: any, index: number) {
if (isNaN(+index)) throw new Error('Nan index received for Payment');
this.index = +index;
this.sender = obj.sender;
this.receiver = obj.receiver;
this.timestamp = obj.timestamp;
this.time = obj.time;
this.weiValue = obj.weiValue;
this.weiPaid = obj.weiPaid;
this.isFork = obj.isFork;
this.parentIndex = obj.parentIndex;
this.isForked = obj.isForked;
this.fork1Index = obj.fork1Index;
this.fork2Index = obj.fork2Index;
}

get weiOwed() {
Expand Down Expand Up @@ -64,7 +75,7 @@ export default class SyndicateStore {
this.payments = [];
this.paymentCount = 0;
this.balances = {};
this.loadPayments(0, 10);
this.loadAllPayments();
this.contract.events.PaymentCreated()
.on('data', (event: any) => {
const index = +event.returnValues.index;
Expand All @@ -77,13 +88,49 @@ export default class SyndicateStore {
this.loadPayments(index, 1);
})
.on('error', console.log);
this.contract.events.BalanceUpdated()
.on('data', (event: any) => {
const address = event.returnValues.target;
this.loadBalance(address);
})
.on('error', console.log);
}

/**
* Loads the payment binary tree into an array of payments
**/
async loadPaymentTree(rootIndex: number): Promise<Payment[]> {
const indexes = await this.loadTreeIndexes(rootIndex);
return await Promise.all(
indexes.map((index: number|string) => this._cachedPayment(+index))
);
}

/**
* Loads the tree from the current point forward in time
*
* Recursively constructs array
**/
async loadTreeIndexes(rootIndex: number): Promise<number[]> {
const payment = await this._cachedPayment(rootIndex);
if (!payment.isForked) return [rootIndex];
return [
rootIndex,
...await this.loadTreeIndexes(payment.fork1Index),
...await this.loadTreeIndexes(payment.fork2Index)
];
}

async loadAllPayments() {
await this.loadPaymentCount();
await this.loadPayments(0, this.paymentCount);
}

/**
* Load count payments from offset
**/
async loadPayments(index: number, count: number) {
this.paymentCount = +(await this.contract.methods.paymentCount().call());
await this.loadPaymentCount();
if (this.paymentCount === 0) {
this.payments = [];
return;
Expand All @@ -96,8 +143,7 @@ export default class SyndicateStore {
if (x >= this.paymentCount) break;
const promise = this.contract.methods.payments(x).call()
.then((payment: Payment) => {
payment.index = x;
return new Payment(payment);
return new Payment(payment, x);
});
promises.push(promise);
}
Expand All @@ -108,14 +154,17 @@ export default class SyndicateStore {
this.payments = [...(await Promise.all(promises)), ...this.payments]
.filter((payment: Payment) => {
if (loadedIndexes[payment.index]) return false;
if (+payment.weiValue === 0) return false;
loadedIndexes[payment.index] = true;
return loadedIndexes;
})
.sort((p1: Payment, p2: Payment) => {
return p2.index - p1.index;
})
.reverse();
const accounts = await web3.eth.getAccounts();
await Promise.all(
accounts.map((account: string) => this.loadBalance(account))
);
}

async loadBalance(address: string) {
Expand Down Expand Up @@ -157,8 +206,13 @@ export default class SyndicateStore {
});
}

async _cachedPayment(index: number) {
if (this.payments[index]) return this.payments[index];
return await this.payment(index);
}

async payment(index: number): Promise<Payment> {
return new Payment(await this.contract.methods.payments(index).call());
return new Payment(await this.contract.methods.payments(index).call(), index);
}

async paymentWeiOwed(index: number) {
Expand All @@ -174,7 +228,7 @@ export default class SyndicateStore {
if (networkId === 1) {
return '0x992447bbd9d9e1d98deaa7d6237b3ebd0ced728e';
} else if (networkId === 4) {
return '0x32fa7e03ebb7186ac191387f5d8e276f56d5a92b';
return '0x5852ca0707d97418096ad073c9520fab37632c07';
} else {
throw new Error(`Invalid networkId: ${networkId} supplied to addressForNetwork`);
}
Expand Down
Loading