import dapp
This commit is contained in:
parent
7cedde3b84
commit
b1f2c2f0b7
|
@ -171,21 +171,18 @@ contract StatusPay is BlockConsumer {
|
|||
// allow direct payment without Keycard from owner
|
||||
if (!payer.exists) {
|
||||
payer = accounts[owners[signer]];
|
||||
require(payer.exists, "no account for this Keycard");
|
||||
}
|
||||
|
||||
// check that a keycard is associated to this account
|
||||
require(payer.exists, "no account for this Keycard");
|
||||
|
||||
// check that the payee exists
|
||||
Account storage payee = accounts[_payment.to];
|
||||
|
||||
// allow payment through owner address
|
||||
if (!payee.exists) {
|
||||
payee = accounts[owners[_payment.to]];
|
||||
require(payee.exists, "payee account does not exist");
|
||||
}
|
||||
|
||||
require(payee.exists, "payee account does not exist");
|
||||
|
||||
// check that _payment.amount is not greater than the maxTxValue for this currency
|
||||
require(_payment.amount <= payer.maxTxAmount, "amount not allowed");
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Keycard POS</title>
|
||||
|
||||
<!-- Sets initial viewport load and disables zooming -->
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
|
||||
|
||||
<style type="text/css" media="screen">
|
||||
hmtl, body { margin: 0; padding: 0;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>
|
||||
window.statusWeb3 = window.web3;
|
||||
</script>
|
||||
<script src="/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,328 @@
|
|||
const StatusPay = artifacts.require('StatusPay');
|
||||
|
||||
import { recoverTypedSignature } from 'eth-sig-util';
|
||||
|
||||
const addressZero = "0x0000000000000000000000000000000000000000";
|
||||
const tokenAddress = "0xc55cF4B03948D7EBc8b9E8BAD92643703811d162";
|
||||
|
||||
export const NEW_WALLET = 'NEW_WALLET';
|
||||
export const newWallet = () => ({
|
||||
type: NEW_WALLET,
|
||||
});
|
||||
|
||||
export const ETHEREUM_LOAD_ERROR = 'ETHEREUM_LOAD_ERROR';
|
||||
export const ethereumLoadError = (err) => ({
|
||||
type: ETHEREUM_LOAD_ERROR,
|
||||
err: err
|
||||
});
|
||||
|
||||
export const ETHEREUM_LOADED = 'ETHEREUM_LOADED';
|
||||
export const ethereumLoaded = () => ({
|
||||
type: ETHEREUM_LOADED
|
||||
});
|
||||
|
||||
export const LOADING_OWNER = 'LOADING_OWNER';
|
||||
export const loadingOwner = () => ({
|
||||
type: LOADING_OWNER
|
||||
});
|
||||
|
||||
export const OWNER_LOADED = 'OWNER_LOADED';
|
||||
export const ownerLoaded = (owner) => ({
|
||||
type: OWNER_LOADED,
|
||||
owner
|
||||
});
|
||||
|
||||
export const WEB3_ERROR = 'WEB3_ERROR';
|
||||
export const web3Error = (error) => ({
|
||||
type: WEB3_ERROR,
|
||||
error
|
||||
});
|
||||
|
||||
export const LOADING_WALLETS = 'LOADING_WALLETS';
|
||||
export const loadingWallets = () => ({
|
||||
type: LOADING_WALLETS
|
||||
});
|
||||
|
||||
export const WALLETS_LOADED = 'WALLETS_LOADED';
|
||||
export const walletsLoaded = (wallets) => ({
|
||||
type: WALLETS_LOADED,
|
||||
wallets
|
||||
});
|
||||
|
||||
export const COUNTING_WALLETS = 'COUNTING_WALLETS';
|
||||
export const countingWallets = () => ({
|
||||
type: COUNTING_WALLETS
|
||||
});
|
||||
|
||||
export const WALLETS_COUNTED = 'WALLETS_COUNTED';
|
||||
export const walletsCounted = (count) => ({
|
||||
type: WALLETS_COUNTED,
|
||||
count: parseInt(count)
|
||||
});
|
||||
|
||||
export const LOADING_WALLET = 'LOADING_WALLET';
|
||||
export const loadingWallet = () => ({
|
||||
type: LOADING_WALLET,
|
||||
});
|
||||
|
||||
export const WALLET_LOADED = 'WALLET_LOADED';
|
||||
export const walletLoaded = (balance, maxTxValue) => ({
|
||||
type: WALLET_LOADED,
|
||||
balance,
|
||||
maxTxValue,
|
||||
});
|
||||
|
||||
export const NETWORK_ID_LOADED = "NETWORK_ID_LOADED";
|
||||
export const networkIDLoaded = (id) => ({
|
||||
type: NETWORK_ID_LOADED,
|
||||
id
|
||||
});
|
||||
|
||||
export const loadNetworkID = () => {
|
||||
return (dispatch) => {
|
||||
web3.eth.net.getId()
|
||||
.then((id) => dispatch(networkIDLoaded(parseInt(id))))
|
||||
.catch((err) => {
|
||||
dispatch(web3Error(err))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function signPaymentRequest(getState, message, cb) {
|
||||
const state = getState();
|
||||
|
||||
let domain = [
|
||||
{ name: "name", type: "string" },
|
||||
{ name: "version", type: "string" },
|
||||
{ name: "chainId", type: "uint256" },
|
||||
{ name: "verifyingContract", type: "address" }
|
||||
];
|
||||
|
||||
let payment = [
|
||||
{ name: "blockNumber", type: "uint256" },
|
||||
{ name: "blockHash", type: "bytes32" },
|
||||
{ name: "currency", type: "address" },
|
||||
{ name: "amount", type: "uint256" },
|
||||
{ name: "to", type: "address" }
|
||||
];
|
||||
|
||||
let domainData = {
|
||||
name: "StatusPay",
|
||||
version: "1",
|
||||
chainId: state.networkID,
|
||||
verifyingContract: StatusPay.address
|
||||
};
|
||||
|
||||
const data = {
|
||||
types: {
|
||||
EIP712Domain: domain,
|
||||
Payment: payment
|
||||
},
|
||||
primaryType: "Payment",
|
||||
domain: domainData,
|
||||
message: message
|
||||
};
|
||||
|
||||
const dataString = JSON.stringify(data);
|
||||
|
||||
const signer = state.owner;
|
||||
if (window.ethereum && window.ethereum.isStatus) {
|
||||
window.ethereum.send("keycard_signTypedData", [dataString])
|
||||
.then(resp => cb(undefined, resp, data))
|
||||
.catch(err => cb(err, undefined, data));
|
||||
} else {
|
||||
web3.currentProvider.sendAsync({
|
||||
method: "eth_signTypedData_v3",
|
||||
params: [signer, dataString],
|
||||
from: signer
|
||||
}, (err, resp) => cb(err, resp, data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const enableEthereum = () => {
|
||||
if (window.ethereum) {
|
||||
window.web3 = new Web3(ethereum);
|
||||
|
||||
return (dispatch) => {
|
||||
ethereum.enable()
|
||||
.then(() => {
|
||||
window.setTimeout(() => {
|
||||
dispatch(ethereumLoaded());
|
||||
dispatch(loadNetworkID());
|
||||
dispatch(loadOwner());
|
||||
}, 200)
|
||||
})
|
||||
.catch((err) => {
|
||||
dispatch(ethereumLoadError(err));
|
||||
})
|
||||
}
|
||||
} else if (window.web3) {
|
||||
return (dispatch) => {
|
||||
dispatch(ethereumLoaded());
|
||||
window.setTimeout(() => {
|
||||
dispatch(loadNetworkID());
|
||||
dispatch(loadOwner())
|
||||
}, 200)
|
||||
}
|
||||
} else {
|
||||
return ethereumLoadError("no ethereum browser");
|
||||
}
|
||||
};
|
||||
|
||||
export const loadOwner = () => {
|
||||
return (dispatch) => {
|
||||
dispatch(loadingOwner())
|
||||
return web3.eth.getAccounts()
|
||||
.then((accounts) => {
|
||||
const owner = accounts[0];
|
||||
dispatch(ownerLoaded(owner))
|
||||
dispatch(loadOwnerBalance(owner))
|
||||
})
|
||||
.catch((err) => {
|
||||
dispatch(web3Error(err))
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const OWNER_BALANCE_LOADED = "OWNER_BALANCE_LOADED";
|
||||
export const ownerBalanceLoaded = (balance) => ({
|
||||
type: OWNER_BALANCE_LOADED,
|
||||
balance
|
||||
});
|
||||
|
||||
export const loadOwnerBalance = (owner) => {
|
||||
return (dispatch) => {
|
||||
web3.eth.getBalance(owner)
|
||||
.then((balance) => dispatch(ownerBalanceLoaded(balance)))
|
||||
.catch((err) => dispatch(ethereumLoadError(err)))
|
||||
}
|
||||
}
|
||||
|
||||
export const REQUESTING_PAYMENT = "REQUESTING_PAYMENT";
|
||||
export const requestingPayment = () => ({
|
||||
type: REQUESTING_PAYMENT,
|
||||
});
|
||||
|
||||
export const PAYMENT_REQUESTED = "PAYMENT_REQUESTED";
|
||||
export const paymentRequested = () => ({
|
||||
type: PAYMENT_REQUESTED,
|
||||
});
|
||||
|
||||
export const sendPaymentRequest = (walletContract, message, sig) => {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(requestingPayment())
|
||||
const requestPayment = await walletContract.methods.requestPayment(message, sig);
|
||||
const gas = await requestPayment.estimateGas();
|
||||
const receipt = await requestPayment.send({
|
||||
gas: gas
|
||||
});
|
||||
dispatch(paymentRequested())
|
||||
} catch(err) {
|
||||
alert(err)
|
||||
console.error("ERROR: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const loadWallet = (walletAddress, message, sig) => {
|
||||
return async (dispatch) => {
|
||||
dispatch(loadingWallet())
|
||||
|
||||
const jsonInterface = KeycardWallet.options.jsonInterface;
|
||||
const walletContract = new EmbarkJS.Blockchain.Contract({
|
||||
abi: jsonInterface,
|
||||
address: walletAddress,
|
||||
});
|
||||
walletContract.address = walletAddress;
|
||||
|
||||
const erc20Contract = new EmbarkJS.Blockchain.Contract({
|
||||
abi: IERC20.options.jsonInterface,
|
||||
address: tokenAddress,
|
||||
});
|
||||
erc20Contract.address = tokenAddress;
|
||||
|
||||
const balance = await erc20Contract.methods.balanceOf(walletAddress).call();
|
||||
const maxTxValue = await walletContract.methods.tokenMaxTxAmount(tokenAddress).call();
|
||||
|
||||
dispatch(walletLoaded(balance, maxTxValue))
|
||||
dispatch(sendPaymentRequest(walletContract, message, sig))
|
||||
};
|
||||
}
|
||||
|
||||
export const KEYCARD_DISCOVERED = "KEYCARD_DISCOVERED";
|
||||
export const keycardDiscovered = (address) => ({
|
||||
type: KEYCARD_DISCOVERED,
|
||||
address,
|
||||
});
|
||||
|
||||
export const FINDING_WALLET = "FINDING_WALLET";
|
||||
export const findingWallet = () => ({
|
||||
type: FINDING_WALLET,
|
||||
});
|
||||
|
||||
export const WALLET_FOUND = "WALLET_FOUND";
|
||||
export const walletFound = (address) => ({
|
||||
type: WALLET_FOUND,
|
||||
address,
|
||||
});
|
||||
|
||||
export const PAYMENT_AMOUNT_VALUE_CHANGE = "PAYMENT_AMOUNT_VALUE_CHANGE";
|
||||
export const paymentAmountValueChange = (value) => ({
|
||||
type: PAYMENT_AMOUNT_VALUE_CHANGE,
|
||||
value
|
||||
});
|
||||
|
||||
export const findWallet = (keycardAddress, message, sig) => {
|
||||
return async (dispatch) => {
|
||||
dispatch(findingWallet());
|
||||
KeycardWalletFactory.methods.keycardsWallets(keycardAddress).call()
|
||||
.then((address) => {
|
||||
//FIXME: if 0x00, display error
|
||||
if (address === addressZero) {
|
||||
alert("wallet not found")
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(walletFound(address))
|
||||
dispatch(loadWallet(address, message, sig))
|
||||
})
|
||||
.catch((err) => {
|
||||
dispatch(web3Error(err))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const requestPayment = () => {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
let block = await web3.eth.getBlock("latest");
|
||||
const message = {
|
||||
blockNumber: block.number,
|
||||
blockHash: block.hash,
|
||||
currency: tokenAddress,
|
||||
to: state.owner,
|
||||
amount: state.txAmount,
|
||||
}
|
||||
|
||||
try {
|
||||
signPaymentRequest(getState, message, function(err, response, data) {
|
||||
if (err) {
|
||||
dispatch(web3Error(err))
|
||||
} else {
|
||||
const sig = response.result;
|
||||
const address = recoverTypedSignature({
|
||||
data: data,
|
||||
sig: sig,
|
||||
})
|
||||
|
||||
dispatch(keycardDiscovered(address));
|
||||
dispatch(findWallet(address, message, sig));
|
||||
}
|
||||
})
|
||||
} catch(err) {
|
||||
dispatch(web3Error(err))
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import React from 'react';
|
||||
|
||||
import Pos from "../containers/Pos"
|
||||
import KeycardWalletFactory from 'Embark/contracts/KeycardWalletFactory';
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
|
||||
import { compressedAddress } from '../utils';
|
||||
|
||||
const styles = theme => ({
|
||||
loading: {
|
||||
textAlign: "center",
|
||||
padding: 50
|
||||
}
|
||||
});
|
||||
|
||||
const App = (props) => {
|
||||
const loading = <div className={props.classes.loading}>
|
||||
<CircularProgress />
|
||||
</div>;
|
||||
|
||||
let body = loading;
|
||||
if (!props.loadingWeb3 && !props.loadingOwner) {
|
||||
body = <Pos />
|
||||
}
|
||||
|
||||
const networkText = props.networkID ? `(Net ID: ${props.networkID})` : "";
|
||||
|
||||
return (
|
||||
<div>
|
||||
<AppBar style={{ backgroundColor: "#0e1c36", position: "relative" }}>
|
||||
<Toolbar>
|
||||
<Typography variant="h6" color="inherit">
|
||||
Keycard POS
|
||||
<Typography variant="caption" color="inherit">
|
||||
{compressedAddress(KeycardWalletFactory.address)} {networkText}
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
<div>
|
||||
{body}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(App);
|
|
@ -0,0 +1,80 @@
|
|||
import React from 'react';
|
||||
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import Fab from '@material-ui/core/Fab';
|
||||
import CheckIcon from '@material-ui/icons/Check';
|
||||
import InputAdornment from '@material-ui/core/InputAdornment';
|
||||
|
||||
export const compressedAddress = (a, padding) => {
|
||||
padding = padding || 4;
|
||||
return `${a.slice(0, padding + 2)}...${a.slice(a.length - padding)}`
|
||||
}
|
||||
|
||||
const formattedBalance = (balance) => {
|
||||
if (balance) {
|
||||
return web3.utils.fromWei(new web3.utils.BN(balance));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const Pos = ({requestingPayment, paymentRequested, onTapRequest, customerKeycardAddress, findingWallet, customerWalletAddress, loadingWallet, customerWallet, onAmountChange, txAmount}) => {
|
||||
return (
|
||||
<div style={{paddingTop: 32}}>
|
||||
{!requestingPayment && !paymentRequested &&
|
||||
<div style={{marginBottom: 32, textAlign: "center"}}>
|
||||
<TextField margin="dense" label="Transaction amount" type="text" style={{marginBottom: 16}} fullWidth
|
||||
onChange={(event) => onAmountChange(event.currentTarget.value)}
|
||||
value = {txAmount}
|
||||
InputProps={{startAdornment: <InputAdornment position="start" style={{paddingBottom: 7}}>Ξ</InputAdornment>}} />
|
||||
<Button onClick={() => onTapRequest()} size="large" color="primary" variant="contained">
|
||||
REQUEST PAYMENT
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
{requestingPayment &&
|
||||
<div>
|
||||
<div style={{textAlign: "center"}}>
|
||||
<CircularProgress />
|
||||
</div>
|
||||
|
||||
{customerKeycardAddress && <p>
|
||||
Customer Keycard Address: {compressedAddress(customerKeycardAddress)}
|
||||
</p>}
|
||||
|
||||
{findingWallet && <p>
|
||||
finding wallet...
|
||||
</p>}
|
||||
|
||||
{customerWalletAddress && <p>
|
||||
Wallet Address: {compressedAddress(customerWalletAddress)}
|
||||
</p>}
|
||||
|
||||
{loadingWallet && <p>
|
||||
loading wallet...
|
||||
</p>}
|
||||
|
||||
{customerWallet && <p>
|
||||
<strong>Wallet</strong><br />
|
||||
Balance: {formattedBalance(customerWallet.balance)} <br />
|
||||
Max Tx Value: {formattedBalance(customerWallet.maxTxValue)} <br />
|
||||
</p>}
|
||||
</div>
|
||||
}
|
||||
|
||||
{paymentRequested &&
|
||||
<div style={{textAlign: "center"}}>
|
||||
<Fab color="primary">
|
||||
<CheckIcon />
|
||||
</Fab>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Pos;
|
|
@ -0,0 +1,15 @@
|
|||
import { connect } from 'react-redux';
|
||||
import App from '../components/App';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
loadingWeb3: state.loadingWeb3,
|
||||
loadingOwner: state.loadingOwner,
|
||||
networkID: state.networkID,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(App);
|
|
@ -0,0 +1,28 @@
|
|||
import { connect } from 'react-redux';
|
||||
import Pos from '../components/Pos';
|
||||
|
||||
import {
|
||||
requestPayment,
|
||||
paymentAmountValueChange
|
||||
} from "../actions";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
customerKeycardAddress: state.customer.keycardAddress,
|
||||
customerWalletAddress: state.customer.walletAddress,
|
||||
customerWallet: state.customer.wallet,
|
||||
findingWallet: state.findingWallet,
|
||||
loadingWallet: state.loadingWallet,
|
||||
requestingPayment: state.requestingPayment,
|
||||
paymentRequested: state.paymentRequested,
|
||||
txAmount: state.txAmount
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onTapRequest: () => dispatch(requestPayment()),
|
||||
onAmountChange: (value) => dispatch(paymentAmountValueChange(value)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Pos);
|
|
@ -0,0 +1,29 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore, applyMiddleware } from 'redux'
|
||||
import { enableEthereum } from './actions';
|
||||
import rootReducer from './reducers'
|
||||
|
||||
import 'typeface-roboto';
|
||||
|
||||
import { install } from '@material-ui/styles';
|
||||
install();
|
||||
|
||||
import App from './containers/App';
|
||||
|
||||
const store = createStore(rootReducer,
|
||||
applyMiddleware(
|
||||
thunkMiddleware
|
||||
)
|
||||
);
|
||||
|
||||
store.dispatch(enableEthereum());
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>,
|
||||
document.getElementById("root")
|
||||
);
|
|
@ -0,0 +1,134 @@
|
|||
import {
|
||||
ETHEREUM_LOAD_ERROR,
|
||||
WEB3_ERROR,
|
||||
ETHEREUM_LOADED,
|
||||
NETWORK_ID_LOADED,
|
||||
LOADING_OWNER,
|
||||
OWNER_LOADED,
|
||||
OWNER_BALANCE_LOADED,
|
||||
LOADING_WALLETS,
|
||||
WALLETS_LOADED,
|
||||
COUNTING_WALLETS,
|
||||
WALLETS_COUNTED,
|
||||
LOADING_WALLET,
|
||||
WALLET_LOADED,
|
||||
KEYCARD_DISCOVERED,
|
||||
FINDING_WALLET,
|
||||
WALLET_FOUND,
|
||||
REQUESTING_PAYMENT,
|
||||
PAYMENT_REQUESTED,
|
||||
PAYMENT_AMOUNT_VALUE_CHANGE
|
||||
} from "../actions";
|
||||
|
||||
const customerInitialState = {
|
||||
keycardAddress: null,
|
||||
walletAddress: null,
|
||||
wallet: null,
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
loadingWeb3: true,
|
||||
loadingWeb3Error: null,
|
||||
loadingOwner: false,
|
||||
owner: null,
|
||||
ownerBalance: null,
|
||||
customer: customerInitialState,
|
||||
findingWallet: false,
|
||||
loadingWallet: false,
|
||||
requestingPayment: false,
|
||||
paymentRequested: false,
|
||||
txAmount: 0
|
||||
};
|
||||
|
||||
export default function(state, action) {
|
||||
console.log("action", action)
|
||||
console.log("state", state)
|
||||
|
||||
if (typeof state === 'undefined') {
|
||||
return initialState;
|
||||
}
|
||||
|
||||
switch (action.type) {
|
||||
case ETHEREUM_LOAD_ERROR:
|
||||
console.error(action.error)
|
||||
return Object.assign({}, state, {
|
||||
loadingWeb3: false,
|
||||
loadingWeb3Error: action.err
|
||||
});
|
||||
case WEB3_ERROR:
|
||||
console.error(action.error)
|
||||
break;
|
||||
case ETHEREUM_LOADED:
|
||||
return Object.assign({}, state, {
|
||||
loadingWeb3: false,
|
||||
});
|
||||
case NETWORK_ID_LOADED:
|
||||
return Object.assign({}, state, {
|
||||
networkID: action.id,
|
||||
});
|
||||
case LOADING_OWNER:
|
||||
return Object.assign({}, state, {
|
||||
loadingOwner: true,
|
||||
});
|
||||
case OWNER_LOADED:
|
||||
return Object.assign({}, state, {
|
||||
loadingOwner: false,
|
||||
owner: action.owner,
|
||||
});
|
||||
case OWNER_BALANCE_LOADED:
|
||||
return Object.assign({}, state, {
|
||||
ownerBalance: action.balance,
|
||||
});
|
||||
case KEYCARD_DISCOVERED:
|
||||
return Object.assign({}, state, {
|
||||
customer: {
|
||||
...state.customer,
|
||||
keycardAddress: action.address,
|
||||
}
|
||||
});
|
||||
case FINDING_WALLET:
|
||||
return Object.assign({}, state, {
|
||||
findingWallet: true,
|
||||
});
|
||||
case WALLET_FOUND:
|
||||
return Object.assign({}, state, {
|
||||
findingWallet: false,
|
||||
customer: {
|
||||
...state.customer,
|
||||
walletAddress: action.address
|
||||
}
|
||||
});
|
||||
case LOADING_WALLET:
|
||||
return Object.assign({}, state, {
|
||||
loadingWallet: true,
|
||||
});
|
||||
case WALLET_LOADED:
|
||||
const wallet = {
|
||||
balance: action.balance,
|
||||
maxTxValue: action.maxTxValue,
|
||||
}
|
||||
|
||||
return Object.assign({}, state, {
|
||||
loadingWallet: false,
|
||||
customer: {
|
||||
...state.customer,
|
||||
wallet: wallet,
|
||||
}
|
||||
});
|
||||
case REQUESTING_PAYMENT:
|
||||
return Object.assign({}, state, {
|
||||
requestingPayment: true,
|
||||
});
|
||||
case PAYMENT_REQUESTED:
|
||||
return Object.assign({}, state, {
|
||||
requestingPayment: false,
|
||||
paymentRequested: true,
|
||||
});
|
||||
case PAYMENT_AMOUNT_VALUE_CHANGE:
|
||||
return Object.assign({}, state, {
|
||||
txAmount: action.value
|
||||
});
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
export const emptyAddress = "0x0000000000000000000000000000000000000000"
|
||||
|
||||
export const compressedAddress = (a, padding) => {
|
||||
padding = padding || 4;
|
||||
return `${a.slice(0, padding + 2)}...${a.slice(a.length - padding)}`
|
||||
}
|
||||
|
||||
export const isEmptyAddress = (a) =>
|
||||
a == emptyAddress
|
||||
|
|
@ -12,17 +12,26 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eth-optimism/solc": "^0.5.16-alpha.2",
|
||||
"@openzeppelin/cli": "^2.8.2",
|
||||
"@openzeppelin/contracts-ethereum-package": "^2.5.0",
|
||||
"eth-sig-util": "^2.5.3",
|
||||
"minimist": "^1.2.5",
|
||||
"solc": "0.5.16",
|
||||
"truffle": "^5.1.44",
|
||||
"ethers": "^5.0.14"
|
||||
"truffle": "^5.1.46",
|
||||
"ethers": "^5.0.14",
|
||||
"@material-ui/core": "^3.9.3",
|
||||
"@material-ui/icons": "^3.0.2",
|
||||
"@material-ui/styles": "^3.0.0-alpha.10",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-redux": "^6.0.1",
|
||||
"redux": "^4.0.1",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"typeface-roboto": "^0.0.54"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eth-optimism/ovm-toolchain": "^0.0.1-alpha.4",
|
||||
"@eth-optimism/solc": "^0.5.16-alpha.2",
|
||||
"@openzeppelin/cli": "^2.8.2",
|
||||
"@openzeppelin/contracts-ethereum-package": "^2.5.0",
|
||||
"@eth-optimism/ovm-toolchain": "^0.0.1-alpha.7",
|
||||
"@openzeppelin/truffle-upgrades": "^1.0.2",
|
||||
"bip39": "^3.0.2",
|
||||
"ethereumjs-wallet": "^1.0.0"
|
||||
|
|
1683
status-pay/yarn.lock
1683
status-pay/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue