Skip to content

Commit 52e402c

Browse files
authored
Merge pull request #42 from TomAFrench/frontend
Frontend update
2 parents 5a62ac7 + 839ae7c commit 52e402c

32 files changed

+3385
-13788
lines changed

.gitbook.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
root: ./docs/
2+
3+
​structure:
4+
readme: README.md
5+
summary: SUMMARY.md

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ build
1313

1414
# misc
1515
.DS_Store
16-
.env*
16+
.env.*.local
1717

1818
# debug
1919
npm-debug.log*

docs/README.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Welcome to the NoteStream Docs
2+
3+
If you are interested in how to use NoteStream to privately stream Ethereum tokens, then please look at our [Getting Started](./getting_started/README.md) page.
4+
5+
# Github
6+
7+
The codebase for the NoteStream contracts and frontend are hosted publicly on [Github](https://github.com/TomAFrench/NoteStream).
8+
9+
# Networks
10+
11+
As NoteStream is in rapid development, it is currently only deployed on the Rinkeby test network. We hope to deploy to other testnets and subsequently the Ethereum Mainnet in due time.
12+
13+
# Gas Costs
14+
15+
We have not measured the gas costs associated with using NoteStream in detail, however we expect the majority of the cost to be from validating the ZK proof required for all transactions using AZTEC Protocol. Since EIP 1108, this takes in the range of 200,000-300,000 gas which corresponds to roughly 5-6x that of a standard ERC20 token transfer.

docs/SUMMARY.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Summary​
2+
3+
4+
* [Getting Started](getting_started/README.md)
5+
* [Using Aztec notes](using_aztec/README.md)
6+
* [Comparison to other money streaming options](comparison_to_others/README.md)
7+
8+
<!-- ## Use headings to create page groups like this one​
9+
10+
* [First page's title](page1/README.md)
11+
* [Some child page](page1/page1-1.md)
12+
* [Some other child page](part1/page1-2.md)
13+
14+
* [Second page's title](page2/README.md)
15+
* [Some child page](page2/page2-1.md)
16+
* [Some other child page](part2/page2-2.md)
17+
18+
## A second-page group​
19+
20+
* [Yet another page](another-page.md) -->

docs/comparison_to_others/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Sablier

docs/getting_started/README.md

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Getting Started
2+
## Trade ERC20 tokens for ZkAssets
3+
4+
Many of the tokens which you will want to stream are going to be ERC20 tokens such as DAI. These don't have the privacy features needed for NoteStream to work. Luckily we can wrap these tokens into an ZkAsset before we start streaming them.
5+
To do this click the "Deposit ERC20 tokens for private assets" and enter the number of tokens you want to convert into ZkAssets.
6+
7+
## Deposit a note into a stream
8+
9+
You can create a stream by clicking the "Create a new stream" button and then following the shown instructions.
10+
It is important to note that the stream recipient must have registered for an AZTEC address in order for then to be able to receive a stream. This is done automatically upon first visiting the NoteStream website.
11+
12+
## Withdrawing from a stream
13+
14+
The NoteStream app continually calculates the maximum amount which you can withdraw from the streams you are receiving. If you click the "withdraw" button next to the stream you want to withdraw from then a ZK proof will be generated to withdraw this amount from the stream note to your wallet.
15+
16+
## Converting back into ERC20 tokens
17+
18+
Once you have withdrawn your ZkAssets, you can convert them back into ERC20 tokens in much the same way as converting ERC20s into ZkAssets.
19+
Of course, when you convert ZkAssets back into ERC20 tokens you lose the privacy properties given by AZTEC notes. There is also the possibility to leak information on the value of a stream if you immediately convert a withdrawal back into ERC20 tokens.
20+
21+
# Terminology
22+
## AZTEC Note
23+
24+
AZTEC notes can be thought of as tokens on Ethereum for which all balances are encrypted so only their owners can view them.
25+
This is a gross oversimplification as these notes instead work on UTXO model (similar to Bitcoin) rather than then fungible balance model of ERC20 tokens which are all familiar with.
26+
27+
## ZkAsset
28+
29+
A zero knowledge representation of an ERC20 token. For example: DAI is represented by the zkDAI ZkAsset.
30+
31+
## Stream Note
32+
The AZTEC note held by the NoteStream contract for a given stream. This note represents the total value of the stream at any time.
33+
34+
# How it works
35+
## Where is my money held?
36+
37+
Each stream is made up of an AZTEC note locked on the NoteStream smart contract. The logic of this smart contract is such that only the stream's sender or receiver may interact with this note.
38+
39+
## How can my streams be private if everything on Ethereum is public?
40+
41+
You're right that everything that happens on the Ethereum network is available for anyone to inspect, however NoteStream uses AZTEC Protocol which allows funds to be transferred as "notes" for which the value is encrypted. Everyone can see that a stream exists but nobody but you will know how much value it contains.
42+
43+
# Interacting with NoteStream
44+
## Can I cancel streams?
45+
46+
Yes. Both the stream sender and recipient can cancel the stream at any time. This will send the appropriate fraction of the stream note's value to each party and then delete the stream.
47+
Can I modify a stream in progress?
48+
No. We're looking at the possibility to allow a stream's sender to modify a stream in progress in certain ways, e.g. extending the stream by topping up the stream note's value.
49+
50+
# Privacy
51+
52+
There are a number of privacy enhancing measures you can take using ZkAssets which are general rather than NoteStream-specific. Please see ["Using Aztec notes"](./using_aztec/README.md) for more information.
53+
54+
## NoteStream-specific public information
55+
56+
There are two times at which information about the stream is made visible
57+
58+
### Creating a stream
59+
60+
A stream is made up of the following information:
61+
- Sender address
62+
- Recipent address
63+
- Stream note hash
64+
- ZkAsset address
65+
- Start Time
66+
- Stop Time
67+
68+
An observer will then be able to see who is streaming to whom, what kind of token they are streaming and when this stream occurred. e.g.
69+
> Alice streamed Bob an unknown amount of zkDAI represented by the AZTEC note with hash 0x1a3...cE1 from 9:00am until 5:00pm on 12/4/20
70+
71+
### Withdrawing/cancelling a stream
72+
73+
Withdrawal and cancellation transactions leak the same information. Here we discuss a withdrawal transaction as an example.
74+
75+
Each withdrawal transaction includes information on the fraction of the stream's duration which is being withdrawn. This is required such that the NoteStream contract can ensure that the withdrawal is valid.
76+
An observer may then for example see that the recipient is withdrawing a value corresponding to a certain fraction of the remaining value on the stream note.
77+
78+
However it is important to note that without knowledge of the initial value of the stream note then it is impossible to determine the absolute value being withdrawn. e.g.
79+
80+
> Bob withdrew 50% of the value of the stream at 1:00pm on 12/4/20
81+
82+
83+
# Security
84+
## Is NoteStream safe?
85+
Currently there are a number of known security flaws which mean that NoteStream should not be used for any Mainnet funds (as such, there is no current Mainnet deployment.). I'm currently speaking with AZTEC about updates to their SDK in order to fix these.
86+
87+
## How do I know you can't steal my funds?
88+
89+
All Notestream contracts are open source and verified on Etherscan.

docs/using_aztec/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Issues associated with depositing/withdrawing ERC20 tokens
2+
3+
An important factor to keep in mind is that the process of depositing ERC20s into a ZkAsset doesn't immediately make them private, i.e. there will be a transaction visible on the blockchain in which a certain amount of DAI is converted into a number of zkDAI notes.
4+
It's impossible to tell what each individual note is worth but the sum of them must equal the number of ERC20s deposited. In the worst case scenario, if all of those notes are then used in a single transaction (such as creation of a NoteStream stream) then it's obvious that the transaction value is equal to that of the ERC20 deposit.
5+
6+
This might sound like it means that it's impossible to have privacy using ZkAssets as anyone can trace your notes back to when they were deposited. However as people send ZkAssets to each other and notes are split and joined, a given deposit may be linked to a huge amount of notes spread over a vast number of people. We're very quickly at a point where we can see that 1000 people all together own the value from a given deposit but it's impossible to work out exactly who owns what fraction.
7+
8+
## Improving privacy of deposits
9+
10+
Even before this mixing behaviour there are steps you can take to improve your privacy. When depositing ERC20s into a ZkAsset its possible to create a number of notes which have zero value attached. This might sound pointless but it allows you then spend your entire deposit without letting anyone know how much you've spent.
11+
12+
An observer will only be able to tell that your stream is worth at most equal to your deposit but it could be anything less than that.
13+
This behaviour is implemented automatically by the AZTEC sdk so you don't need to worry about it.
14+
15+
## Take aways
16+
17+
In order to improve the privacy of your transactions using ZkAssets it is best to
18+
19+
- Have a long history of transactions using this ZkAsset since your last deposit (idealling receiving ZkAsset funds from other people as well)
20+
- Deposit an amount of ERC20 tokens in excess of what you are planning on immediately streaming.

now.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"version": 2,
3+
"build": {
4+
"env": {
5+
"REACT_APP_SUBGRAPH_URL": "https://api.thegraph.com/subgraphs/name/tomafrench/notestream-rinkeby",
6+
"REACT_APP_NETWORK_ID": "4"
7+
}
8+
}
9+
}

packages/contract-artifacts/package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
"@babel/plugin-proposal-object-rest-spread": "^7.4.0",
1414
"@babel/preset-env": "^7.9.0",
1515
"@babel/preset-typescript": "^7.9.0",
16+
"@typescript-eslint/eslint-plugin-tslint": "^2.27.0",
1617
"eslint": "^5.15.3",
1718
"eslint-config-airbnb-base": "^13.1.0",
1819
"eslint-config-prettier": "^6.0.0",
19-
"eslint-plugin-import": "^2.16.0",
20-
"shx": "^0.3.2"
20+
"eslint-plugin-import": "^2.20.2",
21+
"shx": "^0.3.2",
22+
"typescript": "^3.8.3"
2123
},
2224
"engines": {
2325
"node": ">=8.3"

packages/react-app/.env

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
REACT_APP_SUBGRAPH_URL='https://api.thegraph.com/subgraphs/name/tomafrench/notestream-rinkeby'
2+
REACT_APP_NETWORK_ID=4

packages/react-app/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,18 @@
1717
"@material-ui/icons": "^4.9.1",
1818
"@notestream/contract-artifacts": "^1.0.1",
1919
"aztec.js": "^0.17.0",
20-
"bignumber.js": "^9.0.0",
20+
"bnc-onboard": "^1.7.1",
21+
"ethers": "^4.0.46",
2122
"graphql": "^14.6.0",
2223
"moment": "^2.24.0",
2324
"prop-types": "^15.7.2",
2425
"react": "^16.13.0",
26+
"react-blockies": "^1.4.1",
2527
"react-copy-to-clipboard": "^5.0.2",
2628
"react-dom": "^16.13.0",
2729
"react-router": "^5.1.2",
2830
"react-router-dom": "^5.1.2",
2931
"react-scripts": "3.4.0",
30-
"web3": "^1.2.6",
3132
"zkasset-metadata": "^0.1.2"
3233
},
3334
"devDependencies": {

packages/react-app/src/App.tsx

+29-52
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,18 @@ import AppBar from '@material-ui/core/AppBar';
77
import Tabs from '@material-ui/core/Tabs';
88
import Tab from '@material-ui/core/Tab';
99
import Box from '@material-ui/core/Box';
10-
import Toolbar from '@material-ui/core/Toolbar';
11-
import LocalAtmIcon from '@material-ui/icons/LocalAtm';
1210

1311
import getZkAssetsForNetwork from 'zkasset-metadata';
1412
import { getContractAddressesForNetwork, abis } from '@notestream/contract-artifacts';
15-
import { ApolloClient, ApolloProvider, HttpLink, InMemoryCache } from '@apollo/client';
16-
import Web3 from 'web3';
13+
import { ethers } from 'ethers';
14+
1715
import Status from './components/status';
18-
import getWeb3 from './utils/web3';
1916
import DepositDialog from './components/modals/DepositModal';
2017
import WithdrawDialog from './components/modals/WithdrawModal';
2118
import CreateStreamDialog from './components/modals/CreateStreamModal';
22-
23-
const client = new ApolloClient({
24-
cache: new InMemoryCache(),
25-
link: new HttpLink({
26-
uri: 'https://api.thegraph.com/subgraphs/name/tomafrench/notestream-rinkeby',
27-
}),
28-
});
19+
import { useAddress, useWallet } from './contexts/OnboardContext';
20+
import setupAztec from './utils/setup';
21+
import Header from './components/header/Header';
2922

3023
const useStyles = makeStyles((theme) => ({
3124
layout: {
@@ -73,69 +66,53 @@ function TabPanel(props: any): ReactElement {
7366
);
7467
}
7568

69+
const NETWORK_ID: number = parseInt(process.env.REACT_APP_NETWORK_ID as string, 10);
70+
7671
const App = (): ReactElement => {
7772
const classes = useStyles();
78-
const [userAddress, setUserAddress] = useState('');
73+
const userAddress = useAddress();
74+
const wallet = useWallet();
7975
const [streamContractInstance, setStreamContractInstance] = useState({});
8076
const [value, setValue] = useState(0);
81-
82-
const addresses = getContractAddressesForNetwork(4);
83-
const zkAssets = getZkAssetsForNetwork(4);
77+
const [aztec, setAztec] = useState({} as any);
78+
const addresses = getContractAddressesForNetwork(NETWORK_ID);
79+
const zkAssets = getZkAssetsForNetwork(NETWORK_ID);
8480

8581
useEffect(() => {
86-
async function initialiseAztec(): Promise<void> {
87-
const account = await window.aztec.enable({
88-
contractAddresses: {
89-
ACE: addresses.ACE,
90-
},
91-
apiKey: '9HRKN7S-JSZMRJM-KWSDWSY-B2VSRD9', // API key for use with GSN for free txs.
82+
window.addEventListener('load', () => {
83+
setupAztec(NETWORK_ID).then(() => {
84+
setAztec(window.aztec);
9285
});
93-
if (account) {
94-
console.log('Initialised AZTEC');
95-
}
96-
}
97-
initialiseAztec();
98-
}, [userAddress, addresses]);
86+
});
87+
}, []);
9988

10089
useEffect(() => {
101-
async function init(): Promise<void> {
102-
const web3: Web3 = await getWeb3();
103-
const accounts = await web3.eth.getAccounts();
104-
setUserAddress(accounts[0]);
105-
106-
const streamContract = new web3.eth.Contract(abis.NoteStream, addresses.NoteStream);
90+
if (wallet.provider) {
91+
const signer = new ethers.providers.Web3Provider(wallet.provider).getSigner();
92+
const streamContract = new ethers.Contract(addresses.NoteStream, abis.NoteStream, signer);
10793
setStreamContractInstance(streamContract);
10894
}
109-
init();
110-
}, [addresses.NoteStream]);
95+
}, [wallet.provider, addresses.NoteStream]);
11196

11297
return (
113-
<ApolloProvider client={client}>
114-
<AppBar position="static">
115-
<Toolbar>
116-
<LocalAtmIcon className={classes.icon} />
117-
<Typography variant="h6" className={classes.title}>
118-
NoteStream
119-
</Typography>
120-
{/* <Button className={classes.button} variant="contained" >Connect to Wallet</Button> */}
121-
</Toolbar>
122-
</AppBar>
98+
<>
99+
<Header />
123100
<main className={classes.layout}>
124101
<Paper className={`${classes.pageElement} ${classes.paper}`}>
125102
<Grid container direction="row" justify="space-around" spacing={3}>
126103
<Grid item>
127-
<DepositDialog aztec={window.aztec} zkAssets={zkAssets} userAddress={userAddress} />
104+
<DepositDialog aztec={aztec} zkAssets={zkAssets} userAddress={userAddress} />
128105
</Grid>
129106
<Grid item>
130107
<CreateStreamDialog
131-
aztec={window.aztec}
108+
aztec={aztec}
132109
zkAssets={zkAssets}
133110
userAddress={userAddress}
134111
streamContractInstance={streamContractInstance}
135112
/>
136113
</Grid>
137114
<Grid item>
138-
<WithdrawDialog aztec={window.aztec} zkAssets={zkAssets} userAddress={userAddress} />
115+
<WithdrawDialog aztec={aztec} zkAssets={zkAssets} userAddress={userAddress} />
139116
</Grid>
140117
</Grid>
141118
</Paper>
@@ -151,22 +128,22 @@ const App = (): ReactElement => {
151128
<Status
152129
role="sender"
153130
userAddress={userAddress}
154-
aztec={window.aztec}
131+
aztec={aztec}
155132
streamContractInstance={streamContractInstance}
156133
/>
157134
</TabPanel>
158135
<TabPanel value={value} index={1}>
159136
<Status
160137
role="recipient"
161138
userAddress={userAddress}
162-
aztec={window.aztec}
139+
aztec={aztec}
163140
streamContractInstance={streamContractInstance}
164141
/>
165142
</TabPanel>
166143
</Paper>
167144
</Grid>
168145
</main>
169-
</ApolloProvider>
146+
</>
170147
);
171148
};
172149

0 commit comments

Comments
 (0)